Commit d3f64985 by lijinqi

Merge remote-tracking branch 'origin/develop' into develop

parents 5576e65f 0c1c1ff7
import request from '@/config/axios'
export const getUsersData = async (dateType) => {
return await request.get({
url: `/index/count/getUsersData`,
params:{
dateType : dateType
}
})
}
export const getOrdersData = async(dateType) => {
return await request.get({
url:`/index/count/getOrdersData`,
params:{
dateType : dateType
}
})
}
export const getApiCallsData = async(dateType) => {
return await request.get({
url:`/index/count/getApiCallsData`,
params:{
dateType : dateType
}
})
}
export const getTopBarData = async () => {
return await request.get({
url:`/index/count/getTopBarData`,
})
}
...@@ -47,6 +47,10 @@ export interface OrderVO { ...@@ -47,6 +47,10 @@ export interface OrderVO {
afterSaleStatus?: number | null // 售后状态 afterSaleStatus?: number | null // 售后状态
refundPrice?: number | null // 退款金额 refundPrice?: number | null // 退款金额
// ========== 发票基本信息 ==========
invoiceStatus?: number | null //开票状态
invoiceUrl?: String | null //发票链接
// ========== 营销基本信息 ========== // ========== 营销基本信息 ==========
couponId?: number | null // 优惠劵编号 couponId?: number | null // 优惠劵编号
couponPrice?: number | null // 优惠劵减免金额 couponPrice?: number | null // 优惠劵减免金额
...@@ -171,6 +175,11 @@ export const pickUpOrder = async (id: number) => { ...@@ -171,6 +175,11 @@ export const pickUpOrder = async (id: number) => {
return await request.put({ url: `/trade/order/pick-up-by-id?id=${id}` }) return await request.put({ url: `/trade/order/pick-up-by-id?id=${id}` })
} }
//开具发票
export const issueInvoice = async (data: any) => {
return await request.put({ url: `/trade/order/issue-invoice`, data})
}
// 订单核销 // 订单核销
export const pickUpOrderByVerifyCode = async (pickUpVerifyCode: string) => { export const pickUpOrderByVerifyCode = async (pickUpVerifyCode: string) => {
return await request.put({ return await request.put({
......
...@@ -401,6 +401,25 @@ export const DeliveryTypeEnum = { ...@@ -401,6 +401,25 @@ export const DeliveryTypeEnum = {
name: '到店自提' name: '到店自提'
} }
} }
/**
* 开票状态枚举
*/
export const InvoiceRequestEnum = {
UNINVOICED: {
type: 0,
name: '未开票'
},
INVOICING: {
type: 1,
name: '开票中'
},
INVOICED: {
type: 2,
name: '已开票'
}
}
/** /**
* 交易订单 - 状态 * 交易订单 - 状态
*/ */
......
...@@ -185,6 +185,7 @@ export enum DICT_TYPE { ...@@ -185,6 +185,7 @@ export enum DICT_TYPE {
TRADE_ORDER_STATUS = 'trade_order_status', // 订单 - 状态 TRADE_ORDER_STATUS = 'trade_order_status', // 订单 - 状态
TRADE_ORDER_ITEM_AFTER_SALE_STATUS = 'trade_order_item_after_sale_status', // 订单项 - 售后状态 TRADE_ORDER_ITEM_AFTER_SALE_STATUS = 'trade_order_item_after_sale_status', // 订单项 - 售后状态
TRADE_DELIVERY_TYPE = 'trade_delivery_type', // 配送方式 TRADE_DELIVERY_TYPE = 'trade_delivery_type', // 配送方式
TRADE_INVOICE_STATUS = 'trade_invoice_status',
BROKERAGE_ENABLED_CONDITION = 'brokerage_enabled_condition', // 分佣模式 BROKERAGE_ENABLED_CONDITION = 'brokerage_enabled_condition', // 分佣模式
BROKERAGE_BIND_MODE = 'brokerage_bind_mode', // 分销关系绑定模式 BROKERAGE_BIND_MODE = 'brokerage_bind_mode', // 分销关系绑定模式
BROKERAGE_BANK_NAME = 'brokerage_bank_name', // 佣金提现银行 BROKERAGE_BANK_NAME = 'brokerage_bank_name', // 佣金提现银行
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
<el-col :xl="12" :lg="12" :md="12" :sm="24" :xs="24"> <el-col :xl="12" :lg="12" :md="12" :sm="24" :xs="24">
<div class="flex items-center"> <div class="flex items-center">
<el-avatar :src="avatar" :size="70" class="mr-16px"> <el-avatar :src="avatar" :size="70" class="mr-16px">
<img src="@/assets/imgs/avatar.gif" alt="" /> <img src="@/assets/imgs/avatar.gif" alt="用户头像"/>
</el-avatar> </el-avatar>
<div> <div>
<div class="text-20px"> <div class="text-20px">
...@@ -18,405 +18,348 @@ ...@@ -18,405 +18,348 @@
</div> </div>
</div> </div>
</el-col> </el-col>
<!-- <el-col :xl="12" :lg="12" :md="12" :sm="24" :xs="24">--> <el-col :xl="12" :lg="12" :md="12" :sm="24" :xs="24">
<!-- <div class="h-70px flex items-center justify-end lt-sm:mt-10px">--> <div class="h-70px flex items-center justify-end lt-sm:mt-10px">
<!-- <div class="px-8px text-right">--> <div class="px-8px text-right">
<!-- <div class="mb-16px text-14px text-gray-400">{{ t('workplace.project') }}</div>--> <div class="mb-16px text-14px text-gray-400">{{ '今日新增用户' }}</div>
<!-- <CountTo--> <CountTo
<!-- class="text-20px"--> class="text-20px"
<!-- :start-val="0"--> :start-val="0"
<!-- :end-val="totalSate.project"--> :end-val="todayData.newUsersCount"
<!-- :duration="2600"--> :duration="2600"
<!-- />--> />
<!-- </div>--> </div>
<!-- <el-divider direction="vertical" />--> <el-divider direction="vertical"/>
<!-- <div class="px-8px text-right">--> <div class="px-8px text-right">
<!-- <div class="mb-16px text-14px text-gray-400">{{ t('workplace.toDo') }}</div>--> <div class="mb-16px text-14px text-gray-400">{{ '今日订单' }}</div>
<!-- <CountTo--> <CountTo
<!-- class="text-20px"--> class="text-20px"
<!-- :start-val="0"--> :start-val="0"
<!-- :end-val="totalSate.todo"--> :end-val="todayData.newOrdersCount"
<!-- :duration="2600"--> :duration="2600"
<!-- />--> />
<!-- </div>--> </div>
<!-- <el-divider direction="vertical" border-style="dashed" />--> <el-divider direction="vertical" border-style="dashed"/>
<!-- <div class="px-8px text-right">--> <div class="px-8px text-right">
<!-- <div class="mb-16px text-14px text-gray-400">{{ t('workplace.access') }}</div>--> <div class="mb-16px text-14px text-gray-400">{{ '今日订单金额' }}</div>
<!-- <CountTo--> <CountTo
<!-- class="text-20px"--> class="text-20px"
<!-- :start-val="0"--> :start-val="0"
<!-- :end-val="totalSate.access"--> :end-val="todayData.newOrdersAmount"
<!-- :duration="2600"--> :duration="2600"
<!-- />--> />
<!-- </div>--> </div>
<!-- </div>--> </div>
<!-- </el-col>--> </el-col>
</el-row> </el-row>
</el-skeleton> </el-skeleton>
</el-card> </el-card>
</div>
<!-- <el-row class="mt-8px" :gutter="8" justify="space-between">--> <!-- 统计图 -->
<!-- <el-col :xl="16" :lg="16" :md="24" :sm="24" :xs="24" class="mb-8px">--> <el-row class="mt-8px" :gutter="8" justify="space-between">
<!-- <el-card shadow="never">--> <el-col :xl="24" :lg="24" :md="24" :sm="24" :xs="24" class="mb-8px">
<!-- <template #header>--> <el-card shadow="never" class="mt-8px">
<!-- <div class="h-3 flex justify-between">--> <el-skeleton :loading="loading" animated>
<!-- <span>{{ t('workplace.project') }}</span>--> <el-row :gutter="20" justify="space-between">
<!-- <el-link--> <!-- 用户统计图表 -->
<!-- type="primary"--> <el-col :xl="12" :lg="12" :md="12" :sm="12" :xs="12">
<!-- :underline="false"--> <div style="display: flex; justify-content: flex-end; margin-bottom: 10px;">
<!-- href="https://github.com/yudaocode"--> <el-button
<!-- target="_blank"--> @click="changeUserDateType"
<!-- >--> type="primary"
<!-- {{ t('action.more') }}--> size="small"
<!-- </el-link>--> >
<!-- </div>--> {{ userDateType === 'd' ? '切换月数据' : '切换日数据' }}
<!-- </template>--> </el-button>
<!-- <el-skeleton :loading="loading" animated>--> </div>
<!-- <el-row>--> <el-card shadow="hover" class="mb-8px">
<!-- <el-col--> <el-skeleton :loading="loading" animated>
<!-- v-for="(item, index) in projects"--> <Echart :options="usersChartOption" :height="340"/>
<!-- :key="`card-${index}`"--> </el-skeleton>
<!-- :xl="8"--> </el-card>
<!-- :lg="8"--> </el-col>
<!-- :md="8"-->
<!-- :sm="24"-->
<!-- :xs="24"-->
<!-- >-->
<!-- <el-card-->
<!-- shadow="hover"-->
<!-- class="mr-5px mt-5px cursor-pointer"-->
<!-- @click="handleProjectClick(item.message)"-->
<!-- >-->
<!-- <div class="flex items-center">-->
<!-- <Icon-->
<!-- :icon="item.icon"-->
<!-- :size="25"-->
<!-- class="mr-8px"-->
<!-- :style="{ color: item.color }"-->
<!-- />-->
<!-- <span class="text-16px">{{ item.name }}</span>-->
<!-- </div>-->
<!-- <div class="mt-12px text-12px text-gray-400">{{ t(item.message) }}</div>-->
<!-- <div class="mt-12px flex justify-between text-12px text-gray-400">-->
<!-- <span>{{ item.personal }}</span>-->
<!-- <span>{{ formatTime(item.time, 'yyyy-MM-dd') }}</span>-->
<!-- </div>-->
<!-- </el-card>-->
<!-- </el-col>-->
<!-- </el-row>-->
<!-- </el-skeleton>-->
<!-- </el-card>-->
<!-- <el-card shadow="never" class="mt-8px">--> <el-col :xl="12" :lg="12" :md="12" :sm="12" :xs="12">
<!-- <el-skeleton :loading="loading" animated>--> <div style="display: flex; justify-content: flex-end; margin-bottom: 10px;">
<!-- <el-row :gutter="20" justify="space-between">--> <el-button
<!-- <el-col :xl="10" :lg="10" :md="24" :sm="24" :xs="24">--> @click="changeApiCallsDateType"
<!-- <el-card shadow="hover" class="mb-8px">--> type="primary"
<!-- <el-skeleton :loading="loading" animated>--> size="small"
<!-- <Echart :options="pieOptionsData" :height="280" />--> >
<!-- </el-skeleton>--> {{ apiCallsDateType === 'd' ? '切换月数据' : '切换日数据' }}
<!-- </el-card>--> </el-button>
<!-- </el-col>--> </div>
<!-- <el-col :xl="14" :lg="14" :md="24" :sm="24" :xs="24">--> <el-card shadow="hover" class="mb-8px">
<!-- <el-card shadow="hover" class="mb-8px">--> <el-skeleton :loading="loading" animated>
<!-- <el-skeleton :loading="loading" animated>--> <Echart :options="apiCallChartOptions" :height="340"/>
<!-- <Echart :options="barOptionsData" :height="280" />--> </el-skeleton>
<!-- </el-skeleton>--> </el-card>
<!-- </el-card>--> </el-col>
<!-- </el-col>-->
<!-- </el-row>--> <!-- 第三个图表:折线图-->
<!-- </el-skeleton>--> <el-col :xl="24" :lg="24" :md="24" :sm="24" :xs="24">
<!-- </el-card>--> <div style="display: flex; justify-content: flex-end; margin-bottom: 10px;">
<!-- </el-col>--> <el-button
<!-- <el-col :xl="8" :lg="8" :md="24" :sm="24" :xs="24" class="mb-8px">--> @click="changeOrderDateType"
<!-- <el-card shadow="never">--> type="primary"
<!-- <template #header>--> size="small"
<!-- <div class="h-3 flex justify-between">--> >
<!-- <span>{{ t('workplace.shortcutOperation') }}</span>--> {{ orderDateType === 'd' ? '切换月数据' : '切换日数据' }}
<!-- </div>--> </el-button>
<!-- </template>--> </div>
<!-- <el-skeleton :loading="loading" animated>--> <el-card shadow="hover" class="mb-8px">
<!-- <el-row>--> <el-skeleton :loading="loading" animated>
<!-- <el-col v-for="item in shortcut" :key="`team-${item.name}`" :span="8" class="mb-8px">--> <Echart :options="orderChartOptions" :height="420"/>
<!-- <div class="flex items-center">--> </el-skeleton>
<!-- <Icon :icon="item.icon" class="mr-8px" :style="{ color: item.color }" />--> </el-card>
<!-- <el-link type="default" :underline="false" @click="handleShortcutClick(item.url)">--> </el-col>
<!-- {{ item.name }}--> </el-row>
<!-- </el-link>-->
<!-- </div>-->
<!-- </el-col>--> </el-skeleton>
<!-- </el-row>--> </el-card>
<!-- </el-skeleton>--> </el-col>
<!-- </el-card>--> </el-row>
<!-- <el-card shadow="never" class="mt-8px">--> </div>
<!-- <template #header>-->
<!-- <div class="h-3 flex justify-between">-->
<!-- <span>{{ t('workplace.notice') }}</span>-->
<!-- <el-link type="primary" :underline="false">{{ t('action.more') }}</el-link>-->
<!-- </div>-->
<!-- </template>-->
<!-- <el-skeleton :loading="loading" animated>-->
<!-- <div v-for="(item, index) in notice" :key="`dynamics-${index}`">-->
<!-- <div class="flex items-center">-->
<!-- <el-avatar :src="avatar" :size="35" class="mr-16px">-->
<!-- <img src="@/assets/imgs/avatar.gif" alt="" />-->
<!-- </el-avatar>-->
<!-- <div>-->
<!-- <div class="text-14px">-->
<!-- <Highlight :keys="item.keys.map((v) => t(v))">-->
<!-- {{ item.type }} : {{ item.title }}-->
<!-- </Highlight>-->
<!-- </div>-->
<!-- <div class="mt-16px text-12px text-gray-400">-->
<!-- {{ formatTime(item.date, 'yyyy-MM-dd') }}-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- <el-divider />-->
<!-- </div>-->
<!-- </el-skeleton>-->
<!-- </el-card>-->
<!-- </el-col>-->
<!-- </el-row>-->
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { set } from 'lodash-es' import {ref, reactive} from 'vue'
import { EChartsOption } from 'echarts' import {EChartsOption} from 'echarts'
import { formatTime } from '@/utils'
import { useUserStore } from '@/store/modules/user' import {useUserStore} from '@/store/modules/user'
// import { useWatermark } from '@/hooks/web/useWatermark' import type {WorkplaceTotal} from './types'
import type { WorkplaceTotal, Project, Notice, Shortcut } from './types' import {useRouter} from 'vue-router'
import { pieOptions, barOptions } from './echarts-data' import {useI18n} from 'vue-i18n' // 确保导入i18n
import { useRouter } from 'vue-router' import * as IndexCountApi from "@/api/Home/count";
import Index from "@/views/ai/music/index/index.vue";
defineOptions({ name: 'Index' }) defineOptions({name: 'Index'})
const { t } = useI18n() // 国际化
const {t} = useI18n()
const router = useRouter() const router = useRouter()
const userStore = useUserStore() const userStore = useUserStore()
// const { setWatermark } = useWatermark()
const loading = ref(true) const loading = ref(true)
const avatar = userStore.getUser.avatar const avatar = userStore.getUser.avatar
const username = userStore.getUser.nickname const username = userStore.getUser.nickname
const pieOptionsData = reactive<EChartsOption>(pieOptions) as EChartsOption
// 获取统计数
let totalSate = reactive<WorkplaceTotal>({
project: 0,
access: 0,
todo: 0
})
const getCount = async () => { // 切换状态(d=日,m=月)
const data = { const userDateType = ref('d');
project: 40, const apiCallsDateType = ref('d');
access: 2340, const orderDateType = ref('d');
todo: 10
} const changeUserDateType = () => {
totalSate = Object.assign(totalSate, data) userDateType.value = userDateType.value === 'd' ? 'm' : 'd';
// 调用获取图表数据的方法,传入当前类型
getUsersChartData(userDateType.value);
};
const changeApiCallsDateType = () => {
apiCallsDateType.value = apiCallsDateType.value === 'd' ? 'm' : 'd';
getApiCallsChartData(apiCallsDateType.value);
} }
// 获取项目数 const changeOrderDateType = () => {
let projects = reactive<Project[]>([]) orderDateType.value = orderDateType.value === 'd' ? 'm' : 'd';
const getProject = async () => { getOrderChartData(orderDateType.value);
const data = [ }
{
name: 'ruoyi-vue-pro', // 统计数据
icon: 'simple-icons:springboot', const todayData = reactive<WorkplaceTotal>({
message: 'github.com/YunaiV/ruoyi-vue-pro', newUsersCount: 0,
personal: 'Spring Boot 单体架构', newOrdersCount: 0,
time: new Date('2025-01-02'), newOrdersAmount: 0
color: '#6DB33F' })
},
{ // 用户数柱状图配置
name: 'yudao-ui-admin-vue3', const usersChartOption = ref<EChartsOption>({
icon: 'ep:element-plus', title: {
message: 'github.com/yudaocode/yudao-ui-admin-vue3', text: '用户数',
personal: 'Vue3 + element-plus 管理后台', left: 'center'
time: new Date('2025-02-03'), },
color: '#409EFF' tooltip: {
}, trigger: 'axis'
{ },
name: 'yudao-ui-mall-uniapp', xAxis: {
icon: 'icon-park-outline:mall-bag', type: 'category',
message: 'github.com/yudaocode/yudao-ui-mall-uniapp', data: []
personal: 'Vue3 + uniapp 商城手机端', },
time: new Date('2025-03-04'), yAxis: {
color: '#ff4d4f' type: 'value'
}, },
{ series: [
name: 'yudao-cloud',
icon: 'material-symbols:cloud-outline',
message: 'github.com/YunaiV/yudao-cloud',
personal: 'Spring Cloud 微服务架构',
time: new Date('2025-04-05'),
color: '#1890ff'
},
{
name: 'yudao-ui-admin-vben',
icon: 'devicon:antdesign',
message: 'github.com/yudaocode/yudao-ui-admin-vben',
personal: 'Vue3 + vben5(antd) 管理后台',
time: new Date('2025-05-06'),
color: '#e18525'
},
{ {
name: 'yudao-ui-admin-uniapp', name: t('analysis.activeQuantity'),
icon: 'ant-design:mobile', data: [],
message: 'github.com/yudaocode/yudao-ui-admin-uniapp', type: 'bar', // 柱状图
personal: 'Vue3 + uniapp 管理手机端', itemStyle: {
time: new Date('2025-06-01'), color: '#409EFF' // 自定义颜色
color: '#2979ff' }
} }
] ]
projects = Object.assign(projects, data) })
// 用户数柱状图数据
const getUsersChartData = async (userDateType) => {
let responseData = await IndexCountApi.getUsersData(userDateType);
// 直接修改图表配置
usersChartOption.value.xAxis!.data = responseData.map(item => t(item.countDate))
usersChartOption.value.series![0].data = responseData.map(item => item.usersCount)
} }
// 获取通知公告 // api调用折线图配置
let notice = reactive<Notice[]>([]) const apiCallChartOptions = ref<EChartsOption>({
const getNotice = async () => { title: {
const data = [ text: 'api调用次数',
{ left: 'center'
title: '系统支持 JDK 8/17/21,Vue 2/3', },
type: '技术兼容性', tooltip: {
keys: ['JDK', 'Vue'], trigger: 'axis'
date: new Date() },
}, xAxis: {
type: 'category',
data: [] // 后续会动态填充
},
yAxis: {
type: 'value'
},
series: [
{ {
title: '后端提供 Spring Boot 2.7/3.2 + Cloud 双架构', name: 'API调用次数',
type: '架构灵活性', data: [], // 后续会动态填充
keys: ['Boot', 'Cloud'], type: 'line', // 明确指定为折线图
date: new Date() smooth: false, // 平滑曲线
}, itemStyle: {
{ color: '#67C23A' // 自定义颜色
title: '全部开源,个人与企业可 100% 直接使用,无需授权', }
type: '开源免授权',
keys: ['无需授权'],
date: new Date()
},
{
title: '国内使用最广泛的快速开发平台,远超 10w+ 企业使用',
type: '广泛企业认可',
keys: ['最广泛', '10w+'],
date: new Date()
} }
] ]
notice = Object.assign(notice, data) })
}
// 获取快捷入口 // api调用折线图数据
let shortcut = reactive<Shortcut[]>([]) const getApiCallsChartData = async (apiCallsDateType) => {
let data = await IndexCountApi.getApiCallsData(apiCallsDateType)
// 直接修改图表配置
apiCallChartOptions.value.xAxis!.data = data.map(item => t(item.countDate))
apiCallChartOptions.value.series![0].data = data.map(item => item.callsCount)
}
const getShortcut = async () => { //订单折线图配置
const data = [ const orderChartOptions = ref<EChartsOption>({
title: {
text: '订单相关统计',
left: 'center'
},
tooltip: {
trigger: 'axis'
},
xAxis: {
type: 'category',
data: [] // 后续会动态填充
},
yAxis: [
{ {
name: '首页', type: 'value',
icon: 'ion:home-outline', name: '订单数量'
url: '/',
color: '#1fdaca'
}, },
{ {
name: '商城中心', // 右Y轴:金额(新增轴,index=1)
icon: 'ep:shop', type: 'value',
url: '/mall/home', name: '金额(元)', // 轴名称
color: '#ff6b6b' position: 'right' // 放在右侧
}, }
],
series: [
{ {
name: 'AI 大模型', name: '算力订单',
icon: 'tabler:ai', data: [], // 后续会动态填充
url: '/ai/chat', type: 'line', // 明确指定为折线图
color: '#7c3aed' smooth: false, // 平滑曲线
itemStyle: {
color: '#67C23A' // 自定义颜色
}
}, {
name: 'API订单',
data: [], // 后续会动态填充
type: 'line', // 明确指定为折线图
smooth: false, // 平滑曲线
itemStyle: {
color: '#409EFF' // 自定义颜色
}
}, {
name: '总订单',
data: [], // 后续会动态填充
type: 'line', // 明确指定为折线图
smooth: false, // 平滑曲线
itemStyle: {
color: '#F59E0B' // 自定义颜色
}
}, },
// ---------------------- 新增3个金额系列(都绑右侧轴)----------------------
{ {
name: 'ERP 系统', name: '算力订单金额',
icon: 'simple-icons:erpnext', data: [], // 算力金额数据
url: '/erp/home', type: 'line',
color: '#3fb27f' smooth: false,
itemStyle: { color: '#94D274' }, // 浅绿(和算力订单数颜色呼应)
yAxisIndex: 1 // 关键:绑右侧金额轴
}, },
{ {
name: 'CRM 系统', name: 'API订单金额',
icon: 'simple-icons:civicrm', data: [], // API金额数据
url: '/crm/backlog', type: 'line',
color: '#4daf1bc9' smooth: false,
itemStyle: { color: '#7CB6FF' }, // 浅蓝(和API订单数颜色呼应)
yAxisIndex: 1 // 绑右侧金额轴
}, },
{ {
name: 'IoT 物联网', name: '总金额',
icon: 'fa-solid:hdd', data: [], // 总金额数据
url: '/iot/home', type: 'line',
color: '#1a73e8' smooth: false,
itemStyle: { color: '#FFC53D' }, // 浅黄(和总订单数颜色呼应)
yAxisIndex: 1 // 绑右侧金额轴
} }
] ]
shortcut = Object.assign(shortcut, data) })
}
// 用户来源 //订单折线图数据
const getUserAccessSource = async () => { const getOrderChartData = async (orderDateType) => {
const data = [ let ordersData = await IndexCountApi.getOrdersData(orderDateType);
{ value: 335, name: 'analysis.directAccess' },
{ value: 310, name: 'analysis.mailMarketing' },
{ value: 234, name: 'analysis.allianceAdvertising' },
{ value: 135, name: 'analysis.videoAdvertising' },
{ value: 1548, name: 'analysis.searchEngines' }
]
set(
pieOptionsData,
'legend.data',
data.map((v) => t(v.name))
)
pieOptionsData!.series![0].data = data.map((v) => {
return {
name: t(v.name),
value: v.value
}
})
}
const barOptionsData = reactive<EChartsOption>(barOptions) as EChartsOption
// 周活跃量 orderChartOptions.value.xAxis!.data = ordersData.map(item => t(item.countDate))
const getWeeklyUserActivity = async () => { orderChartOptions.value.series![0].data = ordersData.map(item => item.computeOrdersCount)
const data = [ orderChartOptions.value.series![1].data = ordersData.map(item => item.apiOrdersCount)
{ value: 13253, name: 'analysis.monday' }, orderChartOptions.value.series![2].data = ordersData.map(item => item.totalOrdersCount)
{ value: 34235, name: 'analysis.tuesday' }, orderChartOptions.value.series![3].data = ordersData.map(item => item.computeOrdersAmount)
{ value: 26321, name: 'analysis.wednesday' }, orderChartOptions.value.series![4].data = ordersData.map(item => item.apiOrdersAmount)
{ value: 12340, name: 'analysis.thursday' }, orderChartOptions.value.series![5].data = ordersData.map(item => item.totalOrdersAmount)
{ value: 24643, name: 'analysis.friday' },
{ value: 1322, name: 'analysis.saturday' },
{ value: 1324, name: 'analysis.sunday' }
]
set(
barOptionsData,
'xAxis.data',
data.map((v) => t(v.name))
)
set(barOptionsData, 'series', [
{
name: t('analysis.activeQuantity'),
data: data.map((v) => v.value),
type: 'bar'
}
])
} }
const getAllApi = async () => { // 初始化数据
const initData = async () => {
await Promise.all([ await Promise.all([
getCount(), getCount(),
getProject(), getUsersChartData(userDateType.value),
getNotice(), getApiCallsChartData(apiCallsDateType.value),
getShortcut(), getOrderChartData(orderDateType.value)
getUserAccessSource(),
getWeeklyUserActivity()
]) ])
loading.value = false loading.value = false
} }
const handleProjectClick = (message: string) => { // 获取统计数
window.open(`https://${message}`, '_blank') const getCount = async () => {
} // 模拟接口数据
// const data = {
const handleShortcutClick = (url: string) => { // newUsersCount: 10,
router.push(url) // newOrdersCount: 40,
// newOrdersAmount: 2340
// }
let res = await IndexCountApi.getTopBarData()
Object.assign(todayData, res)
} }
initData()
getAllApi()
</script> </script>
export type WorkplaceTotal = { export type WorkplaceTotal = {
project: number newUsersCount: number
access: number newOrdersCount: number
todo: number newOrdersAmount: number
} }
export type Project = { export type Project = {
......
...@@ -24,6 +24,9 @@ ...@@ -24,6 +24,9 @@
订单状态 订单状态
</div> </div>
<div :style="{ width: orderTableHeadWidthList[7] + 'px' }" class="flex justify-center"> <div :style="{ width: orderTableHeadWidthList[7] + 'px' }" class="flex justify-center">
开票状态
</div>
<div :style="{ width: orderTableHeadWidthList[8] + 'px' }" class="flex justify-center">
操作 操作
</div> </div>
</div> </div>
...@@ -156,6 +159,11 @@ ...@@ -156,6 +159,11 @@
<dict-tag :type="DICT_TYPE.TRADE_ORDER_STATUS" :value="scope.row.status" /> <dict-tag :type="DICT_TYPE.TRADE_ORDER_STATUS" :value="scope.row.status" />
</template> </template>
</el-table-column> </el-table-column>
<el-table-column align="center" label="开票状态" width="120">
<template #default>
<dict-tag :type="DICT_TYPE.TRADE_INVOICE_STATUS" :value="scope.row.invoiceStatus" />
</template>
</el-table-column>
<el-table-column align="center" fixed="right" label="操作" width="160"> <el-table-column align="center" fixed="right" label="操作" width="160">
<template #default> <template #default>
<slot :row="scope.row"></slot> <slot :row="scope.row"></slot>
...@@ -236,7 +244,7 @@ const setOrderTableRef = (el: TableInstance) => { ...@@ -236,7 +244,7 @@ const setOrderTableRef = (el: TableInstance) => {
tableHeadWidthAuto(el) tableHeadWidthAuto(el)
} }
// 头部 col 宽度初始化 // 头部 col 宽度初始化
const orderTableHeadWidthList = ref([300, 150, 120, 120, 160, 120, 120, 160]) const orderTableHeadWidthList = ref([300, 150, 120, 120, 160, 120, 120, 120, 160])
// 头部宽度自适应 // 头部宽度自适应
const tableHeadWidthAuto = (el: TableInstance) => { const tableHeadWidthAuto = (el: TableInstance) => {
const columns = el.store.states.columns.value const columns = el.store.states.columns.value
......
<template>
<Dialog v-model="dialogVisible" title="上传发票" width="45%">
<el-form-item label="发票地址" prop="invoiceUrl">
<UploadImg v-model="formData.invoiceUrl" />
<p class="upload-tips">
请上传 大小不超过 <span class="red-text">5MB</span> 格式为
<span class="red-text">png/jpg/jpeg</span>
的文件
</p>
</el-form-item>
<template #footer>
<el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
<el-button @click="dialogVisible = false">取 消</el-button>
</template>
</Dialog>
</template>
<script setup lang="ts">
import * as TradeOrderApi from "@/api/mall/trade/order";
const { t } = useI18n() // 国际化
const message = useMessage() // 消息弹窗
const dialogVisible = ref(false) // 弹窗是否展示
const formRef = ref() // 表单 Ref
const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
/** 提交表单 */
const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
const submitForm = async () => {
// 提交请求
formLoading.value = true
try {
const data = unref(formData)
await TradeOrderApi.issueInvoice(data)
message.success(t('common.updateSuccess'))
dialogVisible.value = false
// 发送操作成功的事件
emit('success', true)
} catch (error) {
console.error(error);
}finally {
formLoading.value = false
}
}
const formData = ref({
id: undefined, // 订单编号
invoiceStatus: undefined,
invoiceUrl: ''
})
const open = async (row: TradeOrderApi.OrderVO) => {
resetForm()
// 设置数据
formData.value.id = row.id
formData.value.invoiceStatus = row.invoiceStatus
formData.value.invoiceUrl = row.invoiceUrl
dialogVisible.value = true
}
defineExpose({ open }) // 提供 open 方法,用于打开弹窗
/** 重置表单 */
const resetForm = () => {
formData.value = {
id: undefined, // 订单编号
invoiceStatus: undefined,
invoiceUrl: ''
}
formRef.value?.resetFields()
}
</script>
<style scoped lang="scss">
</style>
<template>
<!-- 图片查看弹窗 -->
<el-dialog
v-model="dialogVisible"
title="查看发票图片"
:width="`600px`"
:close-on-click-modal="false">
<div class="flex justify-center p-4">
<img
:src="formData.invoiceUrl"
alt="发票图片"
class="max-w-full max-h-[500px] object-contain"
@error="handleImageError"
/>
</div>
</el-dialog>
</template>
<script setup lang="ts">
import * as TradeOrderApi from "@/api/mall/trade/order";
const dialogVisible = ref(false) // 弹窗是否展示
const formData = ref({
id: undefined, // 订单编号
invoiceStatus: undefined,
invoiceUrl: ''
})
const open = async (row: TradeOrderApi.OrderVO) => {
resetForm()
// 设置数据
formData.value.id = row.id
formData.value.invoiceStatus = row.invoiceStatus
formData.value.invoiceUrl = row.invoiceUrl
dialogVisible.value = true
}
defineExpose({open}) // 提供 open 方法,用于打开弹窗
/** 重置表单 */
const resetForm = () => {
formData.value = {
id: undefined, // 订单编号
invoiceStatus: undefined,
invoiceUrl: ''
}
}
const handleImageError = (e) => {
e.target.src = 'https://picsum.photos/600/400?grayscale&blur=2'; // 占位图
e.target.alt = '图片加载失败';
};
</script>
<style scoped lang="scss">
</style>
...@@ -201,6 +201,23 @@ ...@@ -201,6 +201,23 @@
<Icon icon="ep:takeaway-box" /> <Icon icon="ep:takeaway-box" />
发货 发货
</el-dropdown-item> </el-dropdown-item>
<!-- 如果订单开票状态为【未开票】【开票中】,则展示【开票】按钮-->
<el-dropdown-item
v-if="
row.invoiceStatus === InvoiceRequestEnum.UNINVOICED.type ||
row.invoiceStatus === InvoiceRequestEnum.INVOICING.type
"
command="issueInvoice"
>
<Icon icon="ep:takeaway-box" />
开票
</el-dropdown-item>
<el-dropdown-item
v-if="row.invoiceStatus === InvoiceRequestEnum.INVOICED.type"
command="viewInvoice">
<Icon icon="ep:takeaway-box"/>
展示发票
</el-dropdown-item>
<el-dropdown-item command="remark"> <el-dropdown-item command="remark">
<Icon icon="ep:chat-line-square" /> <Icon icon="ep:chat-line-square" />
备注 备注
...@@ -224,6 +241,8 @@ ...@@ -224,6 +241,8 @@
<!-- 各种操作的弹窗 --> <!-- 各种操作的弹窗 -->
<OrderDeliveryForm ref="deliveryFormRef" @success="getList" /> <OrderDeliveryForm ref="deliveryFormRef" @success="getList" />
<OrderUpdateRemarkForm ref="updateRemarkForm" @success="getList" /> <OrderUpdateRemarkForm ref="updateRemarkForm" @success="getList" />
<OrderIssueInvoiceForm ref="issueInvoiceFormRef" @success="getList" />
<OrderViewInvoiceForm ref="viewInvoiceFormRef" @success="getList" />
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
...@@ -234,7 +253,7 @@ import * as TradeOrderApi from '@/api/mall/trade/order' ...@@ -234,7 +253,7 @@ import * as TradeOrderApi from '@/api/mall/trade/order'
import * as PickUpStoreApi from '@/api/mall/trade/delivery/pickUpStore' import * as PickUpStoreApi from '@/api/mall/trade/delivery/pickUpStore'
import { DICT_TYPE, getIntDictOptions, getStrDictOptions } from '@/utils/dict' import { DICT_TYPE, getIntDictOptions, getStrDictOptions } from '@/utils/dict'
import * as DeliveryExpressApi from '@/api/mall/trade/delivery/express' import * as DeliveryExpressApi from '@/api/mall/trade/delivery/express'
import { DeliveryTypeEnum, TradeOrderStatusEnum } from '@/utils/constants' import {DeliveryTypeEnum, InvoiceRequestEnum, TradeOrderStatusEnum} from '@/utils/constants'
import { OrderTableColumn } from './components' import { OrderTableColumn } from './components'
defineOptions({ name: 'TradeOrder' }) defineOptions({ name: 'TradeOrder' })
...@@ -327,6 +346,8 @@ const openDetail = (id: number) => { ...@@ -327,6 +346,8 @@ const openDetail = (id: number) => {
/** 操作分发 */ /** 操作分发 */
const deliveryFormRef = ref() const deliveryFormRef = ref()
const updateRemarkForm = ref() const updateRemarkForm = ref()
const issueInvoiceFormRef = ref()
const viewInvoiceFormRef = ref()
const handleCommand = (command: string, row: TradeOrderApi.OrderVO) => { const handleCommand = (command: string, row: TradeOrderApi.OrderVO) => {
switch (command) { switch (command) {
case 'remark': case 'remark':
...@@ -335,6 +356,12 @@ const handleCommand = (command: string, row: TradeOrderApi.OrderVO) => { ...@@ -335,6 +356,12 @@ const handleCommand = (command: string, row: TradeOrderApi.OrderVO) => {
case 'delivery': case 'delivery':
deliveryFormRef.value?.open(row) deliveryFormRef.value?.open(row)
break break
case 'issueInvoice':
issueInvoiceFormRef.value?.open(row)
break
case 'viewInvoice':
viewInvoiceFormRef.value?.open(row)
break
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment