Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
phsl
/
admin
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
d3f64985
authored
Sep 12, 2025
by
lijinqi
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'origin/develop' into develop
parents
5576e65f
0c1c1ff7
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
539 additions
and
356 deletions
+539
-356
src/api/Home/count/index.ts
+36
-0
src/api/mall/trade/order/index.ts
+9
-0
src/utils/constants.ts
+19
-0
src/utils/dict.ts
+1
-0
src/views/Home/Index.vue
+294
-351
src/views/Home/types.ts
+3
-3
src/views/mall/trade/order/components/OrderTableColumn.vue
+9
-1
src/views/mall/trade/order/form/OrderIssueInvoiceForm.vue
+79
-0
src/views/mall/trade/order/form/OrderViewInvoiceForm.vue
+61
-0
src/views/mall/trade/order/index.vue
+28
-1
No files found.
src/api/Home/count/index.ts
0 → 100644
View file @
d3f64985
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`
,
})
}
src/api/mall/trade/order/index.ts
View file @
d3f64985
...
...
@@ -47,6 +47,10 @@ export interface OrderVO {
afterSaleStatus
?:
number
|
null
// 售后状态
refundPrice
?:
number
|
null
// 退款金额
// ========== 发票基本信息 ==========
invoiceStatus
?:
number
|
null
//开票状态
invoiceUrl
?:
String
|
null
//发票链接
// ========== 营销基本信息 ==========
couponId
?:
number
|
null
// 优惠劵编号
couponPrice
?:
number
|
null
// 优惠劵减免金额
...
...
@@ -171,6 +175,11 @@ export const pickUpOrder = async (id: number) => {
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
)
=>
{
return
await
request
.
put
({
...
...
src/utils/constants.ts
View file @
d3f64985
...
...
@@ -401,6 +401,25 @@ export const DeliveryTypeEnum = {
name
:
'到店自提'
}
}
/**
* 开票状态枚举
*/
export
const
InvoiceRequestEnum
=
{
UNINVOICED
:
{
type
:
0
,
name
:
'未开票'
},
INVOICING
:
{
type
:
1
,
name
:
'开票中'
},
INVOICED
:
{
type
:
2
,
name
:
'已开票'
}
}
/**
* 交易订单 - 状态
*/
...
...
src/utils/dict.ts
View file @
d3f64985
...
...
@@ -185,6 +185,7 @@ export enum DICT_TYPE {
TRADE_ORDER_STATUS
=
'trade_order_status'
,
// 订单 - 状态
TRADE_ORDER_ITEM_AFTER_SALE_STATUS
=
'trade_order_item_after_sale_status'
,
// 订单项 - 售后状态
TRADE_DELIVERY_TYPE
=
'trade_delivery_type'
,
// 配送方式
TRADE_INVOICE_STATUS
=
'trade_invoice_status'
,
BROKERAGE_ENABLED_CONDITION
=
'brokerage_enabled_condition'
,
// 分佣模式
BROKERAGE_BIND_MODE
=
'brokerage_bind_mode'
,
// 分销关系绑定模式
BROKERAGE_BANK_NAME
=
'brokerage_bank_name'
,
// 佣金提现银行
...
...
src/views/Home/Index.vue
View file @
d3f64985
...
...
@@ -6,7 +6,7 @@
<el-col
:xl=
"12"
:lg=
"12"
:md=
"12"
:sm=
"24"
:xs=
"24"
>
<div
class=
"flex items-center"
>
<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>
<div>
<div
class=
"text-20px"
>
...
...
@@ -18,405 +18,348 @@
</div>
</div>
</el-col>
<!--
<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=
"px-8px text-right"
>
--
>
<!--
<div
class=
"mb-16px text-14px text-gray-400"
>
{{
t
(
'workplace.project'
)
}}
</div>
--
>
<!--
<CountTo-->
<!-- class="text-20px"-->
<!-- :start-val="0"-->
<!-- :end-val="totalSate.project"-->
<!-- :duration="2600"-->
<!-- />--
>
<!--
</div>
--
>
<!--
<el-divider
direction=
"vertical"
/>
--
>
<!--
<div
class=
"px-8px text-right"
>
--
>
<!--
<div
class=
"mb-16px text-14px text-gray-400"
>
{{
t
(
'workplace.toDo'
)
}}
</div>
--
>
<!--
<CountTo-->
<!-- class="text-20px"-->
<!-- :start-val="0"-->
<!-- :end-val="totalSate.todo"-->
<!-- :duration="2600"-->
<!-- />--
>
<!--
</div>
--
>
<!--
<el-divider
direction=
"vertical"
border-style=
"dashed"
/>
--
>
<!--
<div
class=
"px-8px text-right"
>
--
>
<!--
<div
class=
"mb-16px text-14px text-gray-400"
>
{{
t
(
'workplace.access'
)
}}
</div>
--
>
<!--
<CountTo-->
<!-- class="text-20px"-->
<!-- :start-val="0"-->
<!-- :end-val="totalSate.access"-->
<!-- :duration="2600"-->
<!-- />--
>
<!--
</div>
--
>
<!--
</div>
--
>
<!--
</el-col>
--
>
<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=
"px-8px text-right"
>
<div
class=
"mb-16px text-14px text-gray-400"
>
{{
'今日新增用户'
}}
</div
>
<CountTo
class=
"text-20px"
:start-val=
"0"
:end-val=
"todayData.newUsersCount"
:duration=
"2600"
/
>
</div
>
<el-divider
direction=
"vertical"
/
>
<div
class=
"px-8px text-right"
>
<div
class=
"mb-16px text-14px text-gray-400"
>
{{
'今日订单'
}}
</div
>
<CountTo
class=
"text-20px"
:start-val=
"0"
:end-val=
"todayData.newOrdersCount"
:duration=
"2600"
/
>
</div
>
<el-divider
direction=
"vertical"
border-style=
"dashed"
/
>
<div
class=
"px-8px text-right"
>
<div
class=
"mb-16px text-14px text-gray-400"
>
{{
'今日订单金额'
}}
</div
>
<CountTo
class=
"text-20px"
:start-val=
"0"
:end-val=
"todayData.newOrdersAmount"
:duration=
"2600"
/
>
</div
>
</div
>
</el-col
>
</el-row>
</el-skeleton>
</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-card
shadow=
"never"
>
-->
<!--
<template
#
header
>
-->
<!--
<div
class=
"h-3 flex justify-between"
>
-->
<!--
<span>
{{
t
(
'workplace.project'
)
}}
</span>
-->
<!--
<el-link-->
<!-- type="primary"-->
<!-- :underline="false"-->
<!-- href="https://github.com/yudaocode"-->
<!-- target="_blank"-->
<!-- >-->
<!--
{{
t
(
'action.more'
)
}}
-->
<!--
</el-link>
-->
<!--
</div>
-->
<!--
</
template
>
-->
<!-- <el-skeleton :loading="loading" animated>-->
<!-- <el-row>-->
<!-- <el-col-->
<!-- v-for="(item, index) in projects"-->
<!-- :key="`card-${index}`"-->
<!-- :xl="8"-->
<!-- :lg="8"-->
<!-- :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-row
class=
"mt-8px"
:gutter=
"8"
justify=
"space-between"
>
<el-col
:xl=
"24"
:lg=
"24"
:md=
"24"
:sm=
"24"
:xs=
"24"
class=
"mb-8px"
>
<el-card
shadow=
"never"
class=
"mt-8px"
>
<el-skeleton
:loading=
"loading"
animated
>
<el-row
:gutter=
"20"
justify=
"space-between"
>
<!-- 用户统计图表 -->
<el-col
:xl=
"12"
:lg=
"12"
:md=
"12"
:sm=
"12"
:xs=
"12"
>
<div
style=
"display: flex; justify-content: flex-end; margin-bottom: 10px;"
>
<el-button
@
click=
"changeUserDateType"
type=
"primary"
size=
"small"
>
{{
userDateType
===
'd'
?
'切换月数据'
:
'切换日数据'
}}
</el-button>
</div>
<el-card
shadow=
"hover"
class=
"mb-8px"
>
<el-skeleton
:loading=
"loading"
animated
>
<Echart
:options=
"usersChartOption"
:height=
"340"
/>
</el-skeleton>
</el-card>
</el-col>
<!-- <el-card shadow="never" class="mt-8px">-->
<!-- <el-skeleton :loading="loading" animated>-->
<!-- <el-row :gutter="20" justify="space-between">-->
<!-- <el-col :xl="10" :lg="10" :md="24" :sm="24" :xs="24">-->
<!-- <el-card shadow="hover" class="mb-8px">-->
<!-- <el-skeleton :loading="loading" animated>-->
<!-- <Echart :options="pieOptionsData" :height="280" />-->
<!-- </el-skeleton>-->
<!-- </el-card>-->
<!-- </el-col>-->
<!-- <el-col :xl="14" :lg="14" :md="24" :sm="24" :xs="24">-->
<!-- <el-card shadow="hover" class="mb-8px">-->
<!-- <el-skeleton :loading="loading" animated>-->
<!-- <Echart :options="barOptionsData" :height="280" />-->
<!-- </el-skeleton>-->
<!-- </el-card>-->
<!-- </el-col>-->
<!-- </el-row>-->
<!-- </el-skeleton>-->
<!-- </el-card>-->
<!-- </el-col>-->
<!-- <el-col :xl="8" :lg="8" :md="24" :sm="24" :xs="24" class="mb-8px">-->
<!-- <el-card shadow="never">-->
<!-- <template #header>-->
<!-- <div class="h-3 flex justify-between">-->
<!-- <span>{{ t('workplace.shortcutOperation') }}</span>-->
<!-- </div>-->
<!-- </template>-->
<!-- <el-skeleton :loading="loading" animated>-->
<!-- <el-row>-->
<!-- <el-col v-for="item in shortcut" :key="`team-${item.name}`" :span="8" class="mb-8px">-->
<!-- <div class="flex items-center">-->
<!-- <Icon :icon="item.icon" class="mr-8px" :style="{ color: item.color }" />-->
<!-- <el-link type="default" :underline="false" @click="handleShortcutClick(item.url)">-->
<!-- {{ item.name }}-->
<!-- </el-link>-->
<!-- </div>-->
<!-- </el-col>-->
<!-- </el-row>-->
<!-- </el-skeleton>-->
<!-- </el-card>-->
<!-- <el-card shadow="never" class="mt-8px">-->
<!-- <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>-->
<el-col
:xl=
"12"
:lg=
"12"
:md=
"12"
:sm=
"12"
:xs=
"12"
>
<div
style=
"display: flex; justify-content: flex-end; margin-bottom: 10px;"
>
<el-button
@
click=
"changeApiCallsDateType"
type=
"primary"
size=
"small"
>
{{
apiCallsDateType
===
'd'
?
'切换月数据'
:
'切换日数据'
}}
</el-button>
</div>
<el-card
shadow=
"hover"
class=
"mb-8px"
>
<el-skeleton
:loading=
"loading"
animated
>
<Echart
:options=
"apiCallChartOptions"
:height=
"340"
/>
</el-skeleton>
</el-card>
</el-col>
<!-- 第三个图表:折线图-->
<el-col
:xl=
"24"
:lg=
"24"
:md=
"24"
:sm=
"24"
:xs=
"24"
>
<div
style=
"display: flex; justify-content: flex-end; margin-bottom: 10px;"
>
<el-button
@
click=
"changeOrderDateType"
type=
"primary"
size=
"small"
>
{{
orderDateType
===
'd'
?
'切换月数据'
:
'切换日数据'
}}
</el-button>
</div>
<el-card
shadow=
"hover"
class=
"mb-8px"
>
<el-skeleton
:loading=
"loading"
animated
>
<Echart
:options=
"orderChartOptions"
:height=
"420"
/>
</el-skeleton>
</el-card>
</el-col>
</el-row>
</el-skeleton>
</el-card>
</el-col>
</el-row>
</div>
</
template
>
<
script
lang=
"ts"
setup
>
import
{
set
}
from
'lodash-es'
import
{
EChartsOption
}
from
'echarts'
import
{
formatTime
}
from
'@/utils'
import
{
ref
,
reactive
}
from
'vue'
import
{
EChartsOption
}
from
'echarts'
import
{
useUserStore
}
from
'@/store/modules/user'
// import { useWatermark } from '@/hooks/web/useWatermark'
import
type
{
WorkplaceTotal
,
Project
,
Notice
,
Shortcut
}
from
'./types'
import
{
pieOptions
,
barOptions
}
from
'./echarts-data'
import
{
useRouter
}
from
'vue-router'
import
{
useUserStore
}
from
'@/store/modules/user'
import
type
{
WorkplaceTotal
}
from
'./types'
import
{
useRouter
}
from
'vue-router'
import
{
useI18n
}
from
'vue-i18n'
// 确保导入i18n
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
userStore
=
useUserStore
()
// const { setWatermark } = useWatermark()
const
loading
=
ref
(
true
)
const
avatar
=
userStore
.
getUser
.
avatar
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
()
=>
{
const
data
=
{
project
:
40
,
access
:
2340
,
todo
:
10
}
totalSate
=
Object
.
assign
(
totalSate
,
data
)
// 切换状态(d=日,m=月)
const
userDateType
=
ref
(
'd'
);
const
apiCallsDateType
=
ref
(
'd'
);
const
orderDateType
=
ref
(
'd'
);
const
changeUserDateType
=
()
=>
{
userDateType
.
value
=
userDateType
.
value
===
'd'
?
'm'
:
'd'
;
// 调用获取图表数据的方法,传入当前类型
getUsersChartData
(
userDateType
.
value
);
};
const
changeApiCallsDateType
=
()
=>
{
apiCallsDateType
.
value
=
apiCallsDateType
.
value
===
'd'
?
'm'
:
'd'
;
getApiCallsChartData
(
apiCallsDateType
.
value
);
}
// 获取项目数
let
projects
=
reactive
<
Project
[]
>
([])
const
getProject
=
async
()
=>
{
const
data
=
[
{
name
:
'ruoyi-vue-pro'
,
icon
:
'simple-icons:springboot'
,
message
:
'github.com/YunaiV/ruoyi-vue-pro'
,
personal
:
'Spring Boot 单体架构'
,
time
:
new
Date
(
'2025-01-02'
),
color
:
'#6DB33F'
},
{
name
:
'yudao-ui-admin-vue3'
,
icon
:
'ep:element-plus'
,
message
:
'github.com/yudaocode/yudao-ui-admin-vue3'
,
personal
:
'Vue3 + element-plus 管理后台'
,
time
:
new
Date
(
'2025-02-03'
),
color
:
'#409EFF'
},
{
name
:
'yudao-ui-mall-uniapp'
,
icon
:
'icon-park-outline:mall-bag'
,
message
:
'github.com/yudaocode/yudao-ui-mall-uniapp'
,
personal
:
'Vue3 + uniapp 商城手机端'
,
time
:
new
Date
(
'2025-03-04'
),
color
:
'#ff4d4f'
},
{
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'
},
const
changeOrderDateType
=
()
=>
{
orderDateType
.
value
=
orderDateType
.
value
===
'd'
?
'm'
:
'd'
;
getOrderChartData
(
orderDateType
.
value
);
}
// 统计数据
const
todayData
=
reactive
<
WorkplaceTotal
>
({
newUsersCount
:
0
,
newOrdersCount
:
0
,
newOrdersAmount
:
0
})
// 用户数柱状图配置
const
usersChartOption
=
ref
<
EChartsOption
>
({
title
:
{
text
:
'用户数'
,
left
:
'center'
},
tooltip
:
{
trigger
:
'axis'
},
xAxis
:
{
type
:
'category'
,
data
:
[]
},
yAxis
:
{
type
:
'value'
},
series
:
[
{
name
:
'yudao-ui-admin-uniapp'
,
icon
:
'ant-design:mobile'
,
message
:
'github.com/yudaocode/yudao-ui-admin-uniapp'
,
personal
:
'Vue3 + uniapp 管理手机端'
,
time
:
new
Date
(
'2025-06-01'
),
color
:
'#2979ff'
name
:
t
(
'analysis.activeQuantity'
)
,
data
:
[]
,
type
:
'bar'
,
// 柱状图
itemStyle
:
{
color
:
'#409EFF'
// 自定义颜色
}
}
]
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
)
}
// 获取通知公告
let
notice
=
reactive
<
Notice
[]
>
([])
const
getNotice
=
async
()
=>
{
const
data
=
[
{
title
:
'系统支持 JDK 8/17/21,Vue 2/3'
,
type
:
'技术兼容性'
,
keys
:
[
'JDK'
,
'Vue'
],
date
:
new
Date
()
},
// api调用折线图配置
const
apiCallChartOptions
=
ref
<
EChartsOption
>
({
title
:
{
text
:
'api调用次数'
,
left
:
'center'
},
tooltip
:
{
trigger
:
'axis'
},
xAxis
:
{
type
:
'category'
,
data
:
[]
// 后续会动态填充
},
yAxis
:
{
type
:
'value'
},
series
:
[
{
title
:
'后端提供 Spring Boot 2.7/3.2 + Cloud 双架构'
,
type
:
'架构灵活性'
,
keys
:
[
'Boot'
,
'Cloud'
],
date
:
new
Date
()
},
{
title
:
'全部开源,个人与企业可 100% 直接使用,无需授权'
,
type
:
'开源免授权'
,
keys
:
[
'无需授权'
],
date
:
new
Date
()
},
{
title
:
'国内使用最广泛的快速开发平台,远超 10w+ 企业使用'
,
type
:
'广泛企业认可'
,
keys
:
[
'最广泛'
,
'10w+'
],
date
:
new
Date
()
name
:
'API调用次数'
,
data
:
[],
// 后续会动态填充
type
:
'line'
,
// 明确指定为折线图
smooth
:
false
,
// 平滑曲线
itemStyle
:
{
color
:
'#67C23A'
// 自定义颜色
}
}
]
notice
=
Object
.
assign
(
notice
,
data
)
}
})
// 获取快捷入口
let
shortcut
=
reactive
<
Shortcut
[]
>
([])
// api调用折线图数据
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
:
'首页'
,
icon
:
'ion:home-outline'
,
url
:
'/'
,
color
:
'#1fdaca'
type
:
'value'
,
name
:
'订单数量'
},
{
name
:
'商城中心'
,
icon
:
'ep:shop'
,
url
:
'/mall/home'
,
color
:
'#ff6b6b'
},
// 右Y轴:金额(新增轴,index=1)
type
:
'value'
,
name
:
'金额(元)'
,
// 轴名称
position
:
'right'
// 放在右侧
}
],
series
:
[
{
name
:
'AI 大模型'
,
icon
:
'tabler:ai'
,
url
:
'/ai/chat'
,
color
:
'#7c3aed'
name
:
'算力订单'
,
data
:
[],
// 后续会动态填充
type
:
'line'
,
// 明确指定为折线图
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 系统'
,
icon
:
'simple-icons:erpnext'
,
url
:
'/erp/home'
,
color
:
'#3fb27f'
name
:
'算力订单金额'
,
data
:
[],
// 算力金额数据
type
:
'line'
,
smooth
:
false
,
itemStyle
:
{
color
:
'#94D274'
},
// 浅绿(和算力订单数颜色呼应)
yAxisIndex
:
1
// 关键:绑右侧金额轴
},
{
name
:
'CRM 系统'
,
icon
:
'simple-icons:civicrm'
,
url
:
'/crm/backlog'
,
color
:
'#4daf1bc9'
name
:
'API订单金额'
,
data
:
[],
// API金额数据
type
:
'line'
,
smooth
:
false
,
itemStyle
:
{
color
:
'#7CB6FF'
},
// 浅蓝(和API订单数颜色呼应)
yAxisIndex
:
1
// 绑右侧金额轴
},
{
name
:
'IoT 物联网'
,
icon
:
'fa-solid:hdd'
,
url
:
'/iot/home'
,
color
:
'#1a73e8'
name
:
'总金额'
,
data
:
[],
// 总金额数据
type
:
'line'
,
smooth
:
false
,
itemStyle
:
{
color
:
'#FFC53D'
},
// 浅黄(和总订单数颜色呼应)
yAxisIndex
:
1
// 绑右侧金额轴
}
]
shortcut
=
Object
.
assign
(
shortcut
,
data
)
}
})
// 用户来源
const
getUserAccessSource
=
async
()
=>
{
const
data
=
[
{
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
//订单折线图数据
const
getOrderChartData
=
async
(
orderDateType
)
=>
{
let
ordersData
=
await
IndexCountApi
.
getOrdersData
(
orderDateType
);
// 周活跃量
const
getWeeklyUserActivity
=
async
()
=>
{
const
data
=
[
{
value
:
13253
,
name
:
'analysis.monday'
},
{
value
:
34235
,
name
:
'analysis.tuesday'
},
{
value
:
26321
,
name
:
'analysis.wednesday'
},
{
value
:
12340
,
name
:
'analysis.thursday'
},
{
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'
}
])
orderChartOptions
.
value
.
xAxis
!
.
data
=
ordersData
.
map
(
item
=>
t
(
item
.
countDate
))
orderChartOptions
.
value
.
series
!
[
0
].
data
=
ordersData
.
map
(
item
=>
item
.
computeOrdersCount
)
orderChartOptions
.
value
.
series
!
[
1
].
data
=
ordersData
.
map
(
item
=>
item
.
apiOrdersCount
)
orderChartOptions
.
value
.
series
!
[
2
].
data
=
ordersData
.
map
(
item
=>
item
.
totalOrdersCount
)
orderChartOptions
.
value
.
series
!
[
3
].
data
=
ordersData
.
map
(
item
=>
item
.
computeOrdersAmount
)
orderChartOptions
.
value
.
series
!
[
4
].
data
=
ordersData
.
map
(
item
=>
item
.
apiOrdersAmount
)
orderChartOptions
.
value
.
series
!
[
5
].
data
=
ordersData
.
map
(
item
=>
item
.
totalOrdersAmount
)
}
const
getAllApi
=
async
()
=>
{
// 初始化数据
const
initData
=
async
()
=>
{
await
Promise
.
all
([
getCount
(),
getProject
(),
getNotice
(),
getShortcut
(),
getUserAccessSource
(),
getWeeklyUserActivity
()
getUsersChartData
(
userDateType
.
value
),
getApiCallsChartData
(
apiCallsDateType
.
value
),
getOrderChartData
(
orderDateType
.
value
)
])
loading
.
value
=
false
}
const
handleProjectClick
=
(
message
:
string
)
=>
{
window
.
open
(
`https://
${
message
}
`
,
'_blank'
)
}
const
handleShortcutClick
=
(
url
:
string
)
=>
{
router
.
push
(
url
)
// 获取统计数
const
getCount
=
async
()
=>
{
// 模拟接口数据
// const data = {
// newUsersCount: 10,
// newOrdersCount: 40,
// newOrdersAmount: 2340
// }
let
res
=
await
IndexCountApi
.
getTopBarData
()
Object
.
assign
(
todayData
,
res
)
}
getAllApi
()
initData
()
</
script
>
src/views/Home/types.ts
View file @
d3f64985
export
type
WorkplaceTotal
=
{
projec
t
:
number
access
:
number
todo
:
number
newUsersCoun
t
:
number
newOrdersCount
:
number
newOrdersAmount
:
number
}
export
type
Project
=
{
...
...
src/views/mall/trade/order/components/OrderTableColumn.vue
View file @
d3f64985
...
...
@@ -24,6 +24,9 @@
订单状态
</div>
<div
:style=
"
{ width: orderTableHeadWidthList[7] + 'px' }" class="flex justify-center">
开票状态
</div>
<div
:style=
"
{ width: orderTableHeadWidthList[8] + 'px' }" class="flex justify-center">
操作
</div>
</div>
...
...
@@ -156,6 +159,11 @@
<dict-tag
:type=
"DICT_TYPE.TRADE_ORDER_STATUS"
:value=
"scope.row.status"
/>
</
template
>
</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"
>
<
template
#
default
>
<slot
:row=
"scope.row"
></slot>
...
...
@@ -236,7 +244,7 @@ const setOrderTableRef = (el: TableInstance) => {
tableHeadWidthAuto
(
el
)
}
// 头部 col 宽度初始化
const
orderTableHeadWidthList
=
ref
([
300
,
150
,
120
,
120
,
160
,
120
,
120
,
160
])
const
orderTableHeadWidthList
=
ref
([
300
,
150
,
120
,
120
,
160
,
120
,
120
,
1
20
,
1
60
])
// 头部宽度自适应
const
tableHeadWidthAuto
=
(
el
:
TableInstance
)
=>
{
const
columns
=
el
.
store
.
states
.
columns
.
value
...
...
src/views/mall/trade/order/form/OrderIssueInvoiceForm.vue
0 → 100644
View file @
d3f64985
<
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
>
src/views/mall/trade/order/form/OrderViewInvoiceForm.vue
0 → 100644
View file @
d3f64985
<
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
>
src/views/mall/trade/order/index.vue
View file @
d3f64985
...
...
@@ -201,6 +201,23 @@
<Icon
icon=
"ep:takeaway-box"
/>
发货
</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"
>
<Icon
icon=
"ep:chat-line-square"
/>
备注
...
...
@@ -224,6 +241,8 @@
<!-- 各种操作的弹窗 -->
<OrderDeliveryForm
ref=
"deliveryFormRef"
@
success=
"getList"
/>
<OrderUpdateRemarkForm
ref=
"updateRemarkForm"
@
success=
"getList"
/>
<OrderIssueInvoiceForm
ref=
"issueInvoiceFormRef"
@
success=
"getList"
/>
<OrderViewInvoiceForm
ref=
"viewInvoiceFormRef"
@
success=
"getList"
/>
</template>
<
script
lang=
"ts"
setup
>
...
...
@@ -234,7 +253,7 @@ import * as TradeOrderApi from '@/api/mall/trade/order'
import
*
as
PickUpStoreApi
from
'@/api/mall/trade/delivery/pickUpStore'
import
{
DICT_TYPE
,
getIntDictOptions
,
getStrDictOptions
}
from
'@/utils/dict'
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'
defineOptions
({
name
:
'TradeOrder'
})
...
...
@@ -327,6 +346,8 @@ const openDetail = (id: number) => {
/** 操作分发 */
const
deliveryFormRef
=
ref
()
const
updateRemarkForm
=
ref
()
const
issueInvoiceFormRef
=
ref
()
const
viewInvoiceFormRef
=
ref
()
const
handleCommand
=
(
command
:
string
,
row
:
TradeOrderApi
.
OrderVO
)
=>
{
switch
(
command
)
{
case
'remark'
:
...
...
@@ -335,6 +356,12 @@ const handleCommand = (command: string, row: TradeOrderApi.OrderVO) => {
case
'delivery'
:
deliveryFormRef
.
value
?.
open
(
row
)
break
case
'issueInvoice'
:
issueInvoiceFormRef
.
value
?.
open
(
row
)
break
case
'viewInvoice'
:
viewInvoiceFormRef
.
value
?.
open
(
row
)
break
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment