Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
W
wangxiaolu-sfa-ui
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
sfa
wangxiaolu-sfa-ui
Commits
13773395
提交
13773395
authored
5月 16, 2025
作者:
lidongxu
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'dev'
上级
fcdb03b5
6ee06867
隐藏空白字符变更
内嵌
并排
正在显示
12 个修改的文件
包含
1500 行增加
和
1149 行删除
+1500
-1149
.env.development
.env.development
+6
-2
.env.production
.env.production
+8
-2
.env.staging
.env.staging
+8
-2
index.js
src/dicts/index.js
+17
-0
date.js
src/hooks/date.js
+2
-3
index.vue
src/mobile/views/promotion/plan/index/index.vue
+8
-11
planSearch.vue
src/mobile/views/promotion/plan/index/planSearch.vue
+21
-4
user.js
src/store/modules/user.js
+11
-0
effectivePlan.vue
src/views/promotion/plan/effectivePlan.vue
+1056
-0
index.vue
src/views/promotion/plan/index.vue
+105
-1124
invalidPlan.vue
src/views/promotion/plan/invalidPlan.vue
+255
-0
index.vue
src/views/promotion/task/index.vue
+3
-1
没有找到文件。
.env.development
浏览文件 @
13773395
...
...
@@ -14,4 +14,8 @@ VITE_APP_PROMOTION = '/promotion-api' # 促销
# 飞书服务回调地址(本地测试已经通过并上线,后台飞书登录接口重定向地址已经不是 localhost 了所以本地开发无需使用飞书登录,线上已经可用)
VITE_APP_REDIRECT_URL = 'http://localhost:8085'
# 积木报表服务地址
VITE_APP_REPORT_URL = 'https://sfa-qa.wxl66.cn'
\ No newline at end of file
VITE_APP_REPORT_URL = 'https://sfa-qa.wxl66.cn'
# 模板表格
VITE_APP_PLAN_TEMPLATE_EXCEL = 'https://link-promotion.oss-cn-shanghai.aliyuncs.com/file/%E6%96%B0%E5%A2%9E%E6%88%96%E4%BF%AE%E6%94%B9%E8%AE%A1%E5%88%92-%E6%A8%A1%E6%9D%BF3.0.xlsx'
\ No newline at end of file
.env.production
浏览文件 @
13773395
...
...
@@ -12,4 +12,10 @@ VITE_APP_PROMOTION = 'https://promotion.wxl66.cn' # 促销
# 飞书服务回调地址
VITE_APP_REDIRECT_URL = 'https://sfa.wxl66.cn/link/'
# 积木报表服务地址
VITE_APP_REPORT_URL = 'https://sfa.wxl66.cn'
\ No newline at end of file
VITE_APP_REPORT_URL = 'https://sfa.wxl66.cn'
# 模板表格
VITE_APP_PLAN_TEMPLATE_EXCEL = 'https://link-promotion.oss-cn-shanghai.aliyuncs.com/file/%E6%96%B0%E5%A2%9E%E6%88%96%E4%BF%AE%E6%94%B9%E8%AE%A1%E5%88%92-%E6%A8%A1%E6%9D%BF3.0.xlsx'
\ No newline at end of file
.env.staging
浏览文件 @
13773395
...
...
@@ -12,4 +12,10 @@ VITE_APP_PROMOTION = '/promotion-api' # 促销
# 飞书服务回调地址
VITE_APP_REDIRECT_URL = 'https://sfa-qa.wxl66.cn/'
# 积木报表服务地址
VITE_APP_REPORT_URL = 'https://sfa-qa.wxl66.cn'
\ No newline at end of file
VITE_APP_REPORT_URL = 'https://sfa-qa.wxl66.cn'
# 模板表格
VITE_APP_PLAN_TEMPLATE_EXCEL = 'https://link-promotion.oss-cn-shanghai.aliyuncs.com/file/%E6%96%B0%E5%A2%9E%E6%88%96%E4%BF%AE%E6%94%B9%E8%AE%A1%E5%88%92-%E6%A8%A1%E6%9D%BF3.0.xlsx'
\ No newline at end of file
src/dicts/index.js
浏览文件 @
13773395
...
...
@@ -15,3 +15,19 @@ export const PROMOTION_STATUS = {
export
const
getPromotionActiveStatus
=
(
statusNum
)
=>
{
return
PROMOTION_STATUS
[
statusNum
]
||
{
label
:
'未知状态'
,
value
:
''
}
}
// 促销活动模式
export
const
PROMOTION_ACTIVITY_MODE_LIST
=
[
{
label
:
'单点CP'
,
value
:
'单点CP'
},
{
label
:
'常规MINI秀'
,
value
:
'常规MINI秀'
},
{
label
:
'校园活动'
,
value
:
'校园活动'
}
]
\ No newline at end of file
src/hooks/date.js
浏览文件 @
13773395
...
...
@@ -26,8 +26,7 @@ export const useDatePickerOptions = () => {
text
:
'最近 7 日'
,
value
()
{
const
start
=
new
Date
();
start
.
setTime
(
start
.
getTime
()
-
3600
*
1000
*
24
*
7
);
start
.
setHours
(
0
,
0
,
0
,
0
);
start
.
setDate
((
new
Date
().
getDate
()
-
(
7
-
1
)))
const
end
=
new
Date
();
end
.
setHours
(
23
,
59
,
59
,
59
);
return
[
start
,
end
]
...
...
@@ -36,7 +35,7 @@ export const useDatePickerOptions = () => {
text
:
'最近 30 日'
,
value
()
{
const
start
=
new
Date
();
start
.
setDate
((
new
Date
().
getDate
()
-
30
))
start
.
setDate
((
new
Date
().
getDate
()
-
(
30
-
1
)
))
start
.
setHours
(
0
,
0
,
0
,
0
);
const
end
=
new
Date
();
end
.
setHours
(
23
,
59
,
59
,
59
);
...
...
src/mobile/views/promotion/plan/index/index.vue
浏览文件 @
13773395
...
...
@@ -88,7 +88,7 @@ defineOptions({
import
userStore
from
'@/store/modules/user'
import
{
parseTime
}
from
'@/utils'
import
{
checkPlanExpire
}
from
'@/hooks'
import
{
getPromotionActiveStatus
}
from
'@/dicts'
import
{
PROMOTION_STATUS
,
getPromotionActiveStatus
}
from
'@/dicts'
import
{
getPlanListAPI
,
deletePlanAPI
,
batchUpdatePlanAPI
,
getChargeListAPI
}
from
'@/api'
import
PlanSearch
from
'./planSearch.vue'
import
PickerBelong
from
'../components/PickerBelong'
...
...
@@ -120,16 +120,12 @@ const loading = ref(false)
const
finished
=
ref
(
false
)
// 活动状态
const
planColumns
=
[
{
text
:
'未执行'
,
value
:
'NOT_EXECUTION'
}
,
{
text
:
'执行'
,
value
:
'EXECUTION'
const
planColumns
=
Object
.
values
(
PROMOTION_STATUS
).
map
(
item
=>
{
return
{
text
:
item
.
label
,
value
:
item
.
value
}
]
}
)
// 归属人
const
allEmpolyeeList
=
ref
([])
...
...
@@ -157,7 +153,8 @@ const getPlanList = async () => {
activityEndDate
:
parseTime
(
query
.
activityEndDate
,
"{y
}
-{m
}
-{d
}
"
),
planStatus
:
planColumns
.
find
(
item
=>
item
.
text
===
query
.
planStatus
)?.
value
,
employeeId
:
promotionIdentity
.
value
?
allEmpolyeeList
.
value
.
find
(
o
=>
o
.
employeeNo
===
employeeNo
.
value
)?.
value
:
query
.
employeeId
,
storeNameLike
:
query
.
storeNameLike
storeNameLike
:
query
.
storeNameLike
,
statusType
:
query
.
isDeleted
}
,
}
)
...
...
src/mobile/views/promotion/plan/index/planSearch.vue
浏览文件 @
13773395
...
...
@@ -60,6 +60,17 @@
placeholder=
"请输入店铺名"
@
update:model-value=
"searchByStoreName"
clearable
/>
<!-- 查看有效/已删除计划 -->
<van-field
label=
"计划状态"
>
<
template
#
input
>
<van-radio-group
v-model=
"query.isDeleted"
@
change=
"selIsDeleted"
>
<van-radio
:name=
"undefined"
>
有效
</van-radio>
<van-radio
name=
"INVALID"
>
已删除
</van-radio>
</van-radio-group>
</
template
>
</van-field>
<!-- 重置按钮 -->
<van-button
icon=
"replay"
class=
"reset-btn"
...
...
@@ -144,10 +155,10 @@ const confirmPlan = (val) => {
const
showEmployee
=
ref
(
false
)
// 如果是城市经理,设置默认归属人
watch
(()
=>
props
.
allEmpolyeeList
,
(
newVal
)
=>
{
if
(
newVal
.
length
>
0
&&
promotionIdentity
.
value
)
{
if
(
newVal
.
length
>
0
&&
promotionIdentity
.
value
)
{
props
.
query
.
employeeName
=
newVal
.
find
(
o
=>
o
.
employeeNo
===
userStore
().
employeeNo
)?.
text
props
.
query
.
employeeId
=
newVal
.
find
(
o
=>
o
.
employeeNo
===
userStore
().
employeeNo
)?.
value
}
}
})
// 确定归属人
...
...
@@ -160,7 +171,12 @@ const onEmployeeConfirm = (val) => {
// 店铺名
const
searchByStoreName
=
(
val
)
=>
{
props
.
query
.
storeNameLike
=
val
// props.query.storeNameLike = val
emits
(
'query'
)
}
// 计划状态
const
selIsDeleted
=
()
=>
{
emits
(
'query'
)
}
...
...
@@ -172,9 +188,10 @@ const resetFn = () => {
props
.
query
.
planStatus
=
undefined
if
(
!
promotionIdentity
.
value
)
{
props
.
query
.
employeeName
=
undefined
props
.
query
.
employeeId
=
undefined
props
.
query
.
employeeId
=
undefined
}
props
.
query
.
storeNameLike
=
undefined
props
.
query
.
isDeleted
=
undefined
emits
(
'query'
)
}
...
...
src/store/modules/user.js
浏览文件 @
13773395
...
...
@@ -103,6 +103,17 @@ export default defineStore(
promotionIdentity
(
state
)
{
return
state
.
userInfo
.
privilegeId
===
1
},
// 员工关键信息
empInfo
(
state
)
{
return
{
empId
:
state
.
userInfo
.
userId
,
// 员工 id
empNo
:
state
.
userInfo
.
userName
,
// 员工工号
empName
:
state
.
userInfo
.
nickName
,
// 员工昵称名字
}
},
// 操作人员工工号,姓名,id
employeeInfo
(
state
)
{
return
{
...
...
src/views/promotion/plan/effectivePlan.vue
0 → 100644
浏览文件 @
13773395
<
template
>
<!-- 功能按钮 -->
<el-row
:gutter=
"10"
class=
"mb8"
justify=
"space-between"
>
<el-col
:span=
"1.5"
>
<el-button
type=
"danger"
plain
icon=
"Delete"
:disabled=
"delMultipleBtnDis"
@
click=
"handleDelete"
>
删除
</el-button>
<el-button
type=
"success"
plain
icon=
"Plus"
@
click=
"handleAdd"
>
新增
</el-button>
<el-button
type=
"primary"
plain
icon=
"Edit"
:disabled=
"editMultipleBtnDis"
@
click=
"handleEditBelong"
>
修改归属人
</el-button>
<a
:href=
"planTemplateExcelUrl"
download
class=
"download-a"
>
<el-button
type=
"warning"
plain
icon=
"Download"
>
下载计划模版
</el-button>
</a>
</el-col>
<el-col
:span=
"1.5"
>
<el-upload
class=
"upload-demo"
action=
"#"
accept=
".xls,.xlsx"
:http-request=
"uploadPlanFile"
:show-file-list=
"false"
>
<template
#
trigger
>
<el-button
type=
"primary"
>
{{
isCityManager
?
'城市经理'
:
'职能角色'
}}
{{
'新增计划上传'
}}
</el-button>
</
template
>
</el-upload>
<el-upload
class=
"upload-demo"
action=
"#"
accept=
".xls,.xlsx"
:http-request=
"uploadChangeFile"
:show-file-list=
"false"
>
<
template
#
trigger
>
<el-button
type=
"primary"
>
修改计划上传
</el-button>
</
template
>
</el-upload>
</el-col>
</el-row>
<!-- 表格列表 -->
<el-table
:data=
"tableList"
border
style=
"width: 100%"
show-overflow-tooltip
@
selection-change=
"handleSelectionChange"
:row-class-name=
"tableRowTimeOutClassName"
>
<el-table-column
type=
"selection"
width=
"55"
:selectable=
"selectableFn"
>
</el-table-column>
<el-table-column
v-for=
"item in columns"
:key=
"item.label"
:prop=
"item.prop"
:label=
"item.label"
:width=
"item.width"
:formatter=
"formatter"
:fixed=
"item.fixed"
:show-overflow-tooltip=
"true"
/>
<el-table-column
label=
"操作"
width=
"150"
fixed=
"right"
>
<
template
#
default=
"scope"
>
<el-button
type=
"success"
link
:disabled=
"!selectableFn(scope.row)"
@
click=
"editFn(scope.row)"
>
编辑
</el-button>
<el-button
type=
"danger"
link
:disabled=
"!selectableFn(scope.row)"
@
click=
"deletePlane(scope.row)"
>
删除
</el-button>
</
template
>
</el-table-column>
</el-table>
<!-- 分页 -->
<pagination
:total=
"total"
v-model:page=
"pageNum"
v-model:limit=
"pageSize"
@
pagination=
"getPlanList"
/>
<!-- 弹窗确认上传计划表格 -->
<el-dialog
title=
"上传计划"
v-model=
"uploadPlanDialogVisible"
:close-on-click-modal=
"false"
:close-on-press-escape=
"false"
>
<div>
<!-- 计划表格 -->
<el-table
:data=
"planTableList"
border
style=
"width: 100%"
show-overflow-tooltip
:row-class-name=
"tableRowClassName"
>
<el-table-column
v-for=
"item in confirmTableColumns"
:key=
"item.label"
:prop=
"item.prop"
:label=
"item.label"
:width=
"item.width"
:formatter=
"formatterConfirm"
/>
</el-table>
</div>
<
template
#
footer
>
<div
class=
"dialog-footer"
>
<p
style=
"color: red; float: left;"
>
如果表格有红色行,请根据错误提示修改本地表格重新上传
</p>
<el-button
@
click=
"uploadPlanDialogVisible = false"
>
取消上传
</el-button>
<el-button
type=
"primary"
:disabled=
"!confirmExcelUUID"
@
click=
"confirmPlanBtn"
>
确定保存
</el-button>
</div>
</
template
>
</el-dialog>
<!-- 新增/修改计划 -->
<el-dialog
class=
"add-edit-plan"
:title=
"(addOrEditPlanForm.id ? '修改' : '新增') + '计划'"
v-model=
"addOrEditPlanVisible"
width=
"60%"
>
<!-- 表单 -->
<el-form
:model=
"addOrEditPlanForm"
label-width=
"150px"
:rules=
"addOrEditPlanFormRules"
ref=
"addOrEditPlanRef"
inline
>
<el-row>
<el-col
:span=
"12"
>
<!-- 选择门店 -->
<el-form-item
label=
"选择门店"
prop=
"storeCode"
>
<el-select
v-model=
"addOrEditPlanForm.storeCode"
placeholder=
"请选择门店"
filterable
clearable
@
change=
"selStoreInfo"
remote
:remote-method=
"remoteStoreMethod"
:disabled=
"!!addOrEditPlanForm.id"
>
<el-option
v-for=
"item in storeList"
:key=
"item.value"
:label=
"item.label"
:value=
"item.value"
/>
</el-select>
<p
class=
"info_p"
:class=
"{ info_error: isInfoError }"
>
{{ selecteStoreInfo }}
</p>
<div>
<a
class=
"link"
v-show=
"isInfoError"
target=
"_blank"
href=
"https://cloud.region2.qince.com/sysapp/react/web/main.html#/home"
>
跳转勤策系统
</a>
</div>
</el-form-item>
</el-col>
<el-col
:span=
"12"
>
<!-- 活动日期 -->
<el-form-item
label=
"活动日期"
prop=
"date"
>
<el-date-picker
v-model=
"addOrEditPlanForm.date"
:clearable=
"false"
start-placeholder=
"活动日期"
value-format=
"YYYY-MM-DDTHH:mm:ss"
:disabled-date=
"disabledDateFn"
:disabled=
"!!addOrEditPlanForm.id"
/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<!-- 活动模式 -->
<el-col
:span=
"12"
>
<el-form-item
label=
"活动模式"
prop=
"pattern"
>
<el-select
v-model=
"addOrEditPlanForm.pattern"
placeholder=
"请选择活动模式"
filterable
clearable
@
change=
"selPattern"
>
<el-option
v-for=
"item in activityModeList"
:key=
"item.value"
:label=
"item.label"
:value=
"item.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col
:span=
"12"
>
<!-- 归属人 -->
<el-form-item
label=
"归属人"
prop=
"employeeNo"
>
<el-select
v-model=
"addOrEditPlanForm.employeeNo"
placeholder=
"请选择归属人"
filterable
clearable
:disabled=
"isCityManager"
@
change=
"selEmployee"
>
<el-option
v-for=
"item in belongPerList"
:key=
"item.employeeNo"
:label=
"item.label"
:value=
"item.employeeNo"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col
:span=
"12"
>
<!-- 上班打卡时间 -->
<el-form-item
label=
"上班打卡时间"
prop=
"inTime"
>
<el-time-picker
v-model=
"addOrEditPlanForm.inTime"
placeholder=
"选择时间"
format=
"HH:mm"
value-format=
"HH:mm:ss"
/>
</el-form-item>
</el-col>
<el-col
:span=
"12"
>
<!-- 下班打卡时间 -->
<el-form-item
label=
"下班打卡时间"
prop=
"outTime"
>
<el-time-picker
v-model=
"addOrEditPlanForm.outTime"
placeholder=
"选择时间"
format=
"HH:mm"
value-format=
"HH:mm:ss"
:disabled=
"!addOrEditPlanForm.inTime"
:disabled-hours=
"disabledHours"
:disabled-minutes=
"disabledMinutes"
:disabled-seconds=
"disabledSeconds"
/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col
:span=
"12"
>
<!-- 工资 -->
<el-form-item
label=
"工资"
prop=
"salary"
>
<el-input-number
v-model=
"addOrEditPlanForm.salary"
placeholder=
"请输入工资"
/>
</el-form-item>
</el-col>
<el-col
:span=
"12"
>
<!-- 杂费 -->
<el-form-item
label=
"杂费"
prop=
"incidentals"
>
<el-input-number
v-model=
"addOrEditPlanForm.incidentals"
placeholder=
"请输入杂费"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
<
template
#
footer
>
<div
class=
"dialog-footer"
>
<el-button
type=
"default"
@
click=
"addOrEditPlanVisible = false"
>
取消
</el-button>
<el-button
type=
"primary"
@
click=
"handleAddOrEditPlan"
:disabled=
"isInfoError"
>
确定保存
</el-button>
</div>
</
template
>
</el-dialog>
<!-- 修改计划归属人 -->
<el-dialog
title=
"修改计划归属人"
v-model=
"editPlanEmpVisible"
width=
"60%"
>
<!-- 表单 -->
<el-form
:model=
"editPlanEmpForm"
label-width=
"150px"
:rules=
"editPlanEmpRules"
ref=
"editPlanEmpRef"
inline
>
<el-form-item
label=
"归属人"
prop=
"employeeId"
>
<el-select
v-model=
"editPlanEmpForm.employeeId"
placeholder=
"请选择归属人(搜索)"
filterable
clearable
>
<el-option
v-for=
"item in belongPerList"
:key=
"item.value"
:label=
"item.label"
:value=
"item.value"
/>
</el-select>
</el-form-item>
</el-form>
<!-- 取消确定 -->
<
template
#
footer
>
<div
class=
"dialog-footer"
>
<el-button
type=
"default"
@
click=
"editPlanEmpVisible = false"
>
取消
</el-button>
<el-button
type=
"primary"
@
click=
"handleEditPlanEmp"
:disabled=
"!editPlanEmpForm.employeeId"
>
确定保存
</el-button>
</div>
</
template
>
</el-dialog>
</template>
<
script
setup
>
import
{
v4
as
uuidv4
}
from
'uuid'
;
import
{
getPlanListAPI
,
uploadFileToOSSAPI
,
addPlanAPI
,
savePlanAPI
,
deletePlanAPI
,
addPlanByRoleAPI
,
getChargeListAPI
,
addPlanByWebAPI
,
updatePlanByWebAPI
,
getPlanStoreListAPI
,
updatePlanAPI
,
batchUpdatePlanAPI
}
from
'@/api'
import
{
checkPlanExpire
}
from
'@/hooks'
import
userStore
from
'@/store/modules/user'
import
{
PROMOTION_ACTIVITY_MODE_LIST
,
getPromotionActiveStatus
}
from
'@/dicts'
import
{
parseTime
}
from
'@/utils'
const
props
=
defineProps
({
queryParams
:
{
type
:
Object
,
}
})
const
{
proxy
}
=
getCurrentInstance
();
const
isCityManager
=
userStore
().
promotionIdentity
const
empInfo
=
userStore
().
empInfo
const
planTemplateExcelUrl
=
import
.
meta
.
env
.
VITE_APP_PLAN_TEMPLATE_EXCEL
const
uploadPlanExcelPath
=
`planExcel/
${
new
Date
().
getFullYear
()}
-
${
new
Date
().
getMonth
()
+
1
}
/
${
empInfo
.
empNo
}
/
${
uuidv4
()}
.xlsx`
// 上传计划表格路径
/*************** 删除计划 ***************/
// 批量
const
delMultipleBtnDis
=
ref
(
true
)
const
handleDelete
=
async
()
=>
{
await
proxy
.
$modal
.
confirm
(
'确认删除吗?'
,
'提示'
,
{
confirmButtonText
:
'确定'
,
cancelButtonText
:
'取消'
,
type
:
'warning'
})
await
deletePlanAPI
({
planIds
:
checkedRowList
.
value
.
map
(
o
=>
o
.
id
),
employeeNo
:
empInfo
.
empNo
})
proxy
.
$modal
.
msgSuccess
(
'删除成功'
)
proxy
.
eventBus
.
emit
(
'refreshPlanList'
)
// 刷新计划列表
getPlanList
()
}
// 单条
const
deletePlane
=
(
row
)
=>
{
checkedRowList
.
value
=
[
row
]
handleDelete
()
}
/*************** 新增计划 ***************/
// 批量
const
uploadPlanFile
=
async
(
file
)
=>
{
// 上传计划表格
proxy
.
$modal
.
loading
(
"正在上传数据,请稍后..."
);
const
excelUrl
=
await
uploadFileToOSSAPI
(
uploadPlanExcelPath
,
file
.
file
)
const
targetAPI
=
isCityManager
?
addPlanAPI
:
addPlanByRoleAPI
// 城市经理和职能角色上传接口不同
try
{
const
res
=
await
targetAPI
({
"excelUrl"
:
excelUrl
,
"employeeNo"
:
empInfo
.
empNo
})
planTableList
.
value
=
res
.
data
.
table
confirmExcelUUID
.
value
=
res
.
data
.
uuid
uploadPlanDialogVisible
.
value
=
true
}
finally
{
proxy
.
$modal
.
closeLoading
();
}
// 保证下次还能上传
return
true
}
// 单条
const
handleAdd
=
()
=>
{
resetAddOrEditPlanForm
()
// 城市经理,默认填充归属人
isCityManager
&&
(
addOrEditPlanForm
.
value
.
employeeNo
=
empInfo
.
empNo
)
addOrEditPlanVisible
.
value
=
true
}
/*************** 修改计划 ***************/
// 批量
const
uploadChangeFile
=
async
(
file
)
=>
{
proxy
.
$modal
.
loading
(
"正在上传数据,请稍后..."
);
const
excelUrl
=
await
uploadFileToOSSAPI
(
uploadPlanExcelPath
,
file
.
file
)
try
{
const
res
=
await
updatePlanAPI
({
"excelUrl"
:
excelUrl
,
"employeeNo"
:
empInfo
.
empNo
})
planTableList
.
value
=
res
.
data
.
table
confirmExcelUUID
.
value
=
res
.
data
.
uuid
uploadPlanDialogVisible
.
value
=
true
}
finally
{
proxy
.
$modal
.
closeLoading
();
}
return
true
}
// 单条
const
editFn
=
(
row
)
=>
{
addOrEditPlanForm
.
value
=
{
...
row
,
inTime
:
parseTime
(
row
.
clockInTime
,
"{h}:{i}:{s}"
),
outTime
:
parseTime
(
row
.
clockOutTime
,
"{h}:{i}:{s}"
)
}
addOrEditPlanVisible
.
value
=
true
}
/*************** 新增/修改计划弹框 ***************/
// 新增/编辑计划表单弹框
const
addOrEditPlanVisible
=
ref
(
false
)
const
addOrEditPlanForm
=
ref
({})
const
activityModeList
=
ref
(
PROMOTION_ACTIVITY_MODE_LIST
)
// 活动模式
// 重置表单
const
resetAddOrEditPlanForm
=
()
=>
{
addOrEditPlanForm
.
value
=
{}
selecteStoreInfo
.
value
=
''
isInfoError
.
value
=
false
}
// 表单验证(所有都是必填项)
const
addOrEditPlanFormRules
=
reactive
({
storeCode
:
[
{
required
:
true
,
message
:
'请输入门店编码'
,
trigger
:
'blur'
}
],
date
:
[
{
required
:
true
,
message
:
'请选择活动日期'
,
trigger
:
'blur'
}
],
pattern
:
[
{
required
:
true
,
message
:
'请选择活动模式'
,
trigger
:
'blur'
}
],
employeeNo
:
[
{
required
:
true
,
message
:
'请选择归属人'
,
trigger
:
'blur'
}
],
inTime
:
[
{
required
:
true
,
message
:
'请选择上班打卡时间'
,
trigger
:
'blur'
}
],
outTime
:
[
{
required
:
true
,
message
:
'请选择下班打卡时间'
,
trigger
:
'blur'
}
],
salary
:
[
{
required
:
true
,
message
:
'请输入工资'
,
trigger
:
'blur'
}
],
incidentals
:
[
{
required
:
true
,
message
:
'请输入杂费'
,
trigger
:
'blur'
}
]
})
// 获取门店列表
const
storeList
=
ref
([])
const
allStoreList
=
ref
([])
const
selecteStoreInfo
=
ref
(
''
)
const
isInfoError
=
ref
(
false
)
const
getStoreList
=
async
()
=>
{
const
{
data
}
=
await
getPlanStoreListAPI
({
storeName
:
addOrEditPlanForm
.
value
.
storeName
})
allStoreList
.
value
=
data
storeList
.
value
=
data
.
map
(
item
=>
{
return
{
label
:
item
.
storeName
,
value
:
item
.
storeCode
}
})
}
getStoreList
()
// 选择门店
const
selStoreInfo
=
(
storeCode
)
=>
{
// 从门店列表找到选中的对象
const
storeInfo
=
allStoreList
.
value
.
find
(
item
=>
item
.
storeCode
===
storeCode
)
// 判断门店是否包含必要的三个信息(因为勤测那边的数据一致性不好,所以需要判断)
if
(
storeInfo
)
{
if
(
!
storeInfo
.
dealersName
||
!
storeInfo
.
dealerId
||
!
storeInfo
.
lineName
)
{
isInfoError
.
value
=
true
// 门店系统名称、经销商不可为空,请到勤策中修改;
selecteStoreInfo
.
value
=
"门店系统名称、经销商不可为空,请到勤策中修改:"
}
else
{
isInfoError
.
value
=
false
// 门店系统名称、经销商不可为空,请到勤策中修改;
selecteStoreInfo
.
value
=
storeInfo
.
storeAddr
+
"-"
+
storeInfo
.
storeCode
}
}
else
{
isInfoError
.
value
=
false
// 门店系统名称、经销商不可为空,请到勤策中修改;
selecteStoreInfo
.
value
=
''
}
// 清除表单验证提示
proxy
.
$refs
.
addOrEditPlanRef
.
clearValidate
(
'storeCode'
);
}
// 门店搜索
const
remoteStoreMethod
=
(
query
)
=>
{
addOrEditPlanForm
.
value
.
storeName
=
query
getStoreList
()
}
// 定义禁用日期的函数
const
disabledDateFn
=
(
time
)
=>
{
// 城市经理只能新增下个月一整个月的
if
(
isCityManager
)
{
const
now
=
new
Date
();
const
start
=
new
Date
(
now
.
getFullYear
(),
now
.
getMonth
()
+
1
,
1
);
const
end
=
new
Date
(
now
.
getFullYear
(),
now
.
getMonth
()
+
2
,
0
);
return
time
.
getTime
()
<
start
.
getTime
()
||
time
.
getTime
()
>
end
.
getTime
()
}
else
{
// 职能角色能添加当月今天往后和下个月一整个月
const
now
=
new
Date
();
const
thisMonthStart
=
new
Date
(
now
.
getFullYear
(),
now
.
getMonth
(),
now
.
getDate
());
const
nextMonthEnd
=
new
Date
(
now
.
getFullYear
(),
now
.
getMonth
()
+
2
,
0
);
return
time
.
getTime
()
<
thisMonthStart
.
getTime
()
||
time
.
getTime
()
>
nextMonthEnd
.
getTime
();
}
}
// 根据选择的开始时间,禁用小时分钟秒只能选择之后的时间
const
makeRange
=
(
start
,
end
)
=>
{
const
result
=
[]
for
(
let
i
=
start
;
i
<=
end
;
i
++
)
{
result
.
push
(
i
)
}
return
result
}
const
disabledHours
=
(
h
)
=>
{
// 根据上班时间选择的结果,禁用小时
const
date
=
new
Date
(
addOrEditPlanForm
.
value
.
nTime
)
return
makeRange
(
0
,
date
.
getHours
()
-
1
);
}
const
disabledMinutes
=
(
h
,
m
)
=>
{
// 如果小时大于上班打卡时间小时,则不限制分钟
const
inDate
=
new
Date
(
addOrEditPlanForm
.
value
.
inTime
)
if
(
h
>
inDate
.
getHours
())
{
return
makeRange
(
0
,
-
1
);
}
else
{
const
date
=
new
Date
(
addOrEditPlanForm
.
value
.
inTime
)
return
makeRange
(
0
,
date
.
getMinutes
()
-
1
);
}
}
const
disabledSeconds
=
(
h
,
m
,
s
)
=>
{
const
date
=
new
Date
(
addOrEditPlanForm
.
value
.
inTime
)
return
makeRange
(
0
,
date
.
getSeconds
()
-
1
);
}
// 新增计划表单-选完以后去掉错误提示
const
selPattern
=
()
=>
{
proxy
.
$refs
.
addOrEditPlanRef
.
clearValidate
(
'pattern'
);
}
const
selEmployee
=
()
=>
{
proxy
.
$refs
.
addOrEditPlanRef
.
clearValidate
(
'employeeNo'
);
}
// 保存新增/编辑计划
const
handleAddOrEditPlan
=
async
()
=>
{
// 表单校验
await
proxy
.
$refs
.
addOrEditPlanRef
.
validate
()
// 设置操作人参数给后台
addOrEditPlanForm
.
value
.
operNo
=
empInfo
.
empNo
addOrEditPlanForm
.
value
.
operName
=
empInfo
.
empName
addOrEditPlanForm
.
value
.
operId
=
empInfo
.
empId
const
dataObj
=
{
...
addOrEditPlanForm
.
value
,
// 格式是 xx:xx:xx,替换最后一对 xx 为 00
inTime
:
addOrEditPlanForm
.
value
.
inTime
.
replace
(
/:
\d{2}
$/
,
':00'
),
outTime
:
addOrEditPlanForm
.
value
.
outTime
.
replace
(
/:
\d{2}
$/
,
':00'
)
}
if
(
dataObj
.
id
)
{
// 根据归属人 employeeId 查询它的 id 和名字
const
employeeInfo
=
belongPerList
.
value
.
find
(
item
=>
item
.
employeeNo
===
dataObj
.
employeeNo
)
dataObj
.
employeeId
=
employeeInfo
.
value
dataObj
.
employeeName
=
employeeInfo
.
label
await
updatePlanByWebAPI
(
dataObj
)
}
else
{
await
addPlanByWebAPI
(
dataObj
)
}
proxy
.
$modal
.
msgSuccess
(
'保存成功'
)
addOrEditPlanVisible
.
value
=
false
getPlanList
()
}
/*************** 修改归属人 ***************/
// 批量
const
editMultipleBtnDis
=
ref
(
true
)
const
handleEditBelong
=
()
=>
{
editPlanEmpVisible
.
value
=
true
nextTick
(()
=>
{
editPlanEmpForm
.
value
.
employeeId
=
null
proxy
.
resetForm
(
"editPlanEmpRef"
);
})
}
const
editPlanEmpVisible
=
ref
(
false
)
const
editPlanEmpForm
=
ref
({
employeeId
:
null
})
const
editPlanEmpRules
=
ref
({
employeeId
:
[{
required
:
true
,
message
:
'请选择归属人'
,
trigger
:
'change'
}]
})
// 确定批量修改计划人
const
handleEditPlanEmp
=
async
()
=>
{
const
res
=
await
batchUpdatePlanAPI
({
employeeId
:
editPlanEmpForm
.
value
.
employeeId
,
operName
:
empInfo
.
empName
,
planIds
:
checkedRowList
.
value
.
map
(
item
=>
item
.
id
)
})
proxy
.
$modal
.
msgSuccess
(
res
.
msg
)
editPlanEmpVisible
.
value
=
false
getPlanList
()
}
/*************** 计划表格 ***************/
const
tableList
=
ref
([])
const
columns
=
ref
([
{
label
:
'归属人'
,
prop
:
'employeeName'
,
width
:
150
,
fixed
:
true
},
{
label
:
'战区'
,
prop
:
'orgName'
,
width
:
120
},
{
label
:
'店铺名称'
,
prop
:
'storeName'
,
width
:
240
},
{
label
:
'活动日期'
,
prop
:
'date'
,
width
:
120
},
{
label
:
'星期'
,
prop
:
'week'
,
width
:
80
},
{
label
:
'活动状态'
,
prop
:
'planStatus'
,
width
:
100
},
{
label
:
'活动模式'
,
prop
:
'pattern'
,
width
:
100
},
{
label
:
'系统名称'
,
prop
:
'lineName'
,
width
:
150
},
{
label
:
'店铺编码'
,
prop
:
'storeCode'
,
width
:
160
},
{
label
:
'经销商'
,
prop
:
'dealerName'
,
width
:
220
},
{
label
:
'经销商 ID'
,
prop
:
'dealerId'
,
width
:
120
},
{
label
:
'省份'
,
prop
:
'province'
,
width
:
100
},
{
label
:
'地址'
,
prop
:
'addr'
,
width
:
200
},
{
label
:
'上班时间'
,
prop
:
'clockInTime'
,
width
:
180
},
{
label
:
'下班时间'
,
prop
:
'clockOutTime'
,
width
:
180
},
{
label
:
'促销员薪资'
,
prop
:
'salary'
,
width
:
100
},
{
label
:
'杂费'
,
prop
:
'incidentals'
,
width
:
100
},
{
label
:
'创建人'
,
prop
:
'createBy'
,
width
:
120
},
{
label
:
'最近修改人'
,
prop
:
'modifyBy'
,
width
:
100
},
{
label
:
'最后修改时间'
,
prop
:
'modifyTime'
,
width
:
180
},
{
label
:
'活动 ID'
,
prop
:
'id'
,
width
:
90
}
])
// 格式化计划列表单元格内容
const
formatter
=
(
row
,
col
,
value
)
=>
{
if
(
col
.
property
===
'planStatus'
)
{
return
getPromotionActiveStatus
(
value
)?.
label
}
else
if
(
col
.
property
===
'date'
)
{
// 活动日期
return
parseTime
(
value
,
'{y}-{m}-{d}'
)
}
else
if
(
col
.
property
===
'week'
)
{
return
parseTime
(
row
[
'date'
],
'周{a}'
)
}
else
if
(
col
.
property
===
'modifyTime'
)
{
return
parseTime
(
value
,
'{y}-{m}-{d} {h}:{i}:{s}'
)
}
else
if
(
col
.
property
===
'clockInTime'
||
col
.
property
===
'clockOutTime'
)
{
return
parseTime
(
value
)
}
else
if
(
col
.
property
===
'employeeName'
)
{
// 判断归属人名字小于 4 个字,少于几个就加几个空格
if
(
value
.
length
===
2
)
{
return
value
+
' '
+
'('
+
row
.
employeeNo
+
')'
}
else
if
(
value
.
length
===
3
)
{
return
value
+
' '
+
'('
+
row
.
employeeNo
+
')'
}
else
{
return
value
+
'('
+
row
.
employeeNo
+
')'
}
}
else
if
(
col
.
property
===
'salary'
||
col
.
property
===
'incidentals'
)
{
return
'¥ '
+
value
+
' 元'
}
else
{
return
value
}
}
// 表格复选框的数据
const
checkedRowList
=
ref
([])
const
handleSelectionChange
=
(
val
)
=>
{
checkedRowList
.
value
=
val
delMultipleBtnDis
.
value
=
!
(
checkedRowList
.
value
.
length
>
0
)
editMultipleBtnDis
.
value
=
!
(
checkedRowList
.
value
.
length
>
0
)
}
// 控制表格复选框是否可选
const
selectableFn
=
(
row
)
=>
{
return
checkPlanExpire
(
row
)
}
// 计算当前行类名
const
tableRowTimeOutClassName
=
({
row
})
=>
{
// 检查计划是否能操作
const
isExpire
=
checkPlanExpire
(
row
)
if
(
!
isExpire
)
{
return
'timeout-row'
}
else
{
return
''
}
}
/*************** 数据和分页 ***************/
const
total
=
ref
(
0
)
const
pageNum
=
ref
(
1
)
const
pageSize
=
ref
(
10
)
// 任务列表
const
getPlanList
=
async
(
arg
)
=>
{
if
(
arg
===
'resetPage'
)
pageNum
.
value
=
1
const
res
=
await
getPlanListAPI
({
pageNum
:
pageNum
.
value
,
pageSize
:
pageSize
.
value
,
queryParams
:
{
activityStartDate
:
props
.
queryParams
.
activityDate
&&
props
.
queryParams
.
activityDate
[
0
],
activityEndDate
:
props
.
queryParams
.
activityDate
&&
props
.
queryParams
.
activityDate
[
1
],
planStatus
:
props
.
queryParams
.
planStatus
,
region
:
props
.
queryParams
.
region
,
province
:
props
.
queryParams
.
provinceName
,
city
:
props
.
queryParams
.
cityName
,
dealerId
:
props
.
queryParams
.
dealerId
,
orgQcId
:
props
.
queryParams
.
warZoneId
,
employeeId
:
props
.
queryParams
.
employeeId
,
storeNameLike
:
props
.
queryParams
.
storeName
}
})
tableList
.
value
=
res
.
data
.
records
total
.
value
=
res
.
data
.
totalRecord
}
getPlanList
()
// 归属人列表
const
belongPerList
=
ref
([])
const
getBelongPerList
=
async
()
=>
{
const
{
data
}
=
await
getChargeListAPI
()
belongPerList
.
value
=
data
.
map
(
item
=>
{
return
{
label
:
item
.
name
,
value
:
item
.
id
,
employeeNo
:
item
.
employeeNo
,
deptQcName
:
item
.
deptQcName
,
deptQcId
:
item
.
deptQcId
}
})
}
getBelongPerList
()
/*************** 弹窗上传计划表格(展示) ***************/
const
uploadPlanDialogVisible
=
ref
(
false
)
const
planTableList
=
ref
([])
const
confirmExcelUUID
=
ref
(
''
)
const
confirmTableColumns
=
[
{
label
:
'错误消息'
,
prop
:
'errorMsg'
,
width
:
450
},
{
label
:
'归属人'
,
prop
:
'employeeName'
,
width
:
90
,
fixed
:
true
},
{
label
:
'归属人工号'
,
prop
:
'employeeNo'
,
width
:
140
},
{
label
:
'店铺名称'
,
prop
:
'storeName'
,
width
:
200
},
{
label
:
'店铺编码'
,
prop
:
'storeCode'
,
width
:
160
},
{
label
:
'活动模式'
,
prop
:
'pattern'
,
width
:
100
},
{
label
:
'活动日期'
,
prop
:
'date'
,
width
:
180
},
{
label
:
'上班时间'
,
prop
:
'clockInTime'
,
width
:
180
},
{
label
:
'下班时间'
,
prop
:
'clockOutTime'
,
width
:
180
},
{
label
:
'促销员薪资'
,
prop
:
'salary'
,
width
:
100
},
{
label
:
'杂费'
,
prop
:
'incidentals'
,
width
:
100
},
// {
// label: '活动 ID',
// prop: 'id',
// width: 90,
// // fixed: true
// },
{
label
:
'经销商 ID'
,
prop
:
'dealerId'
,
width
:
120
},
{
label
:
'经销商'
,
prop
:
'dealerName'
,
width
:
220
},
{
label
:
'系统名称'
,
prop
:
'lineName'
,
width
:
100
},
// {
// label: '活动状态',
// prop: 'planStatus',
// width: 100
// },
{
label
:
'省份'
,
prop
:
'province'
,
width
:
100
},
{
label
:
'地址'
,
prop
:
'addr'
,
width
:
200
},
{
label
:
'战区'
,
prop
:
'orgName'
,
width
:
150
},
// {
// label: '城市',
// prop: 'city',
// width: 100
// },
{
label
:
'创建人'
,
prop
:
'createBy'
,
width
:
100
},
{
label
:
'最近修改人'
,
prop
:
'modifyBy'
,
width
:
100
},
{
label
:
'最后修改时间'
,
prop
:
'modifyTime'
,
width
:
250
}
]
const
tableRowClassName
=
({
row
})
=>
{
if
(
row
.
errorMsg
)
{
return
'error-row'
}
else
{
return
''
}
}
const
formatterConfirm
=
(
row
,
col
,
value
)
=>
{
if
(
col
.
property
===
'clockInTime'
||
col
.
property
===
'clockOutTime'
||
col
.
property
===
'date'
)
{
return
parseTime
(
value
)
}
else
if
(
col
.
property
===
'errorMsg'
)
{
// 把分号替换成 \n
return
value
&&
value
.
replace
(
/;/g
,
'
\
n'
)
}
else
{
return
value
}
}
// 表格上传计划确认保存
const
confirmPlanBtn
=
async
()
=>
{
await
savePlanAPI
(
confirmExcelUUID
.
value
)
proxy
.
$modal
.
msgSuccess
(
'保存成功'
)
uploadPlanDialogVisible
.
value
=
false
getPlanList
()
}
defineExpose
({
getPlanList
})
</
script
>
<
style
scoped
lang=
"scss"
>
.el-row
{
/* 下载计划模版 */
.download-a
{
margin-left
:
12px
;
}
/* 上传计划 */
.upload-demo
{
display
:
inline-block
;
margin
:
0
5px
;
}
}
.el-table
{
::v-deep
(
.error-row
)
{
--el-table-tr-bg-color
:
var
(
--
el-color-error-light-9
);
}
/* 灰色过期行颜色 */
::v-deep
(
.timeout-row
)
{
--el-table-tr-bg-color
:
var
(
--
el-timeout-row
);
}
}
/* 新增修改计划表单 */
.add-edit-plan
{
/* 门店列表选择后-下面的介绍信息 */
.info_p
{
margin
:
0
;
font-size
:
12px
;
color
:
gray
;
}
.info_error
{
color
:
rgb
(
167
,
0
,
0
);
}
/* 工资和杂费输入框 */
.el-input-number
{
width
:
170px
;
}
}
</
style
>
\ No newline at end of file
src/views/promotion/plan/index.vue
浏览文件 @
13773395
...
...
@@ -15,7 +15,7 @@
start-placeholder=
"开始日期"
end-placeholder=
"结束日期"
:shortcuts=
"pickerOptions"
@
change=
"
getPlanList
"
/>
@
change=
"
selActivityDate
"
/>
</el-form-item>
<el-form-item
label=
"活动状态"
prop=
"planStatus"
>
...
...
@@ -36,7 +36,7 @@
<el-form-item
label=
"区域查询"
prop=
"region"
>
<el-radio-group
v-model=
"queryParams.region"
@
change=
"
regionChange
"
>
@
change=
"
changeRegion
"
>
<el-radio-button
label=
"全国"
value=
"全国"
/>
<el-radio-button
label=
"省"
...
...
@@ -46,11 +46,11 @@
</el-radio-group>
</el-form-item>
<el-form-item
label=
"省份"
prop=
"province"
prop=
"province
Id
"
v-show=
"queryParams.region !== '全国'"
>
<el-select
v-model=
"queryParams.provinceId"
placeholder=
"请选择省"
@
change=
"
getProCity
"
@
change=
"
selProvince
"
filterable
clearable
>
<el-option
v-for=
"item in provinceList"
...
...
@@ -60,11 +60,11 @@
</el-select>
</el-form-item>
<el-form-item
label=
"城市"
prop=
"city"
prop=
"city
Id
"
v-show=
"queryParams.region === '省-市'"
>
<el-select
v-model=
"queryParams.cityId"
placeholder=
"请选择市"
@
change=
"
getPlanList
"
@
change=
"
selCity
"
filterable
clearable
>
<el-option
v-for=
"item in cityList"
...
...
@@ -76,23 +76,23 @@
</el-row>
<el-row>
<el-form-item
label=
"经销商"
prop=
"
zone
"
>
<el-select
v-model=
"queryParams.
zone
Id"
placeholder=
"搜索经销商"
prop=
"
dealerId
"
>
<el-select
v-model=
"queryParams.
dealer
Id"
placeholder=
"搜索
更多
经销商"
@
change=
"getPlanList"
filterable
remote
:remote-method=
"
zone
RemoteSearch"
:remote-method=
"
dealer
RemoteSearch"
clearable
>
<el-option
v-for=
"item in
zone
List"
<el-option
v-for=
"item in
dealer
List"
:key=
"item.value"
:label=
"item.label"
:value=
"item.value"
/>
</el-select>
</el-form-item>
<el-form-item
label=
"战区"
prop=
"war
zone
"
>
<el-select
v-model=
"queryParams.war
z
oneId"
prop=
"war
ZoneId
"
>
<el-select
v-model=
"queryParams.war
Z
oneId"
placeholder=
"搜索战区"
filterable
clearable
...
...
@@ -105,7 +105,7 @@
</el-select>
</el-form-item>
<el-form-item
label=
"归属人"
prop=
"
belongPer
"
>
prop=
"
employeeId
"
>
<el-select
v-model=
"queryParams.employeeId"
placeholder=
"搜索归属人"
filterable
...
...
@@ -119,7 +119,7 @@
</el-select>
</el-form-item>
<el-form-item
label=
"店铺名"
prop=
"store"
>
prop=
"store
Name
"
>
<el-input
v-model=
"queryParams.storeName"
clearable
placeholder=
"搜索店铺名"
...
...
@@ -127,414 +127,120 @@
</el-form-item>
</el-row>
</el-form>
<el-row
:gutter=
"10"
class=
"mb8"
justify=
"space-between"
>
<el-col
:span=
"1.5"
>
<el-button
type=
"danger"
plain
icon=
"Delete"
:disabled=
"delMultipleBtnDis"
@
click=
"handleDelete"
>
删除
</el-button>
<el-button
type=
"success"
plain
icon=
"Plus"
@
click=
"handleAdd"
>
新增
</el-button>
<el-button
type=
"primary"
plain
icon=
"Edit"
:disabled=
"editMultipleBtnDis"
@
click=
"handleEditEmp"
>
修改归属人
</el-button>
<el-button
type=
"warning"
plain
icon=
"Download"
>
<a
href=
"https://link-promotion.oss-cn-shanghai.aliyuncs.com/file/%E6%96%B0%E5%A2%9E%E6%88%96%E4%BF%AE%E6%94%B9%E8%AE%A1%E5%88%92-%E6%A8%A1%E6%9D%BF3.0.xlsx"
download
>
下载计划模版
</a>
</el-button>
</el-col>
<el-col
:span=
"1.5"
>
<el-upload
class=
"upload-demo"
action=
"#"
accept=
".xls,.xlsx"
:http-request=
"uploadFile"
:show-file-list=
"false"
>
<template
#
trigger
>
<el-button
type=
"primary"
>
{{
isCityManager
?
'城市经理'
:
'职能角色'
}}
{{
'新增计划上传'
}}
</el-button>
</
template
>
</el-upload>
<el-upload
class=
"upload-demo"
action=
"#"
accept=
".xls,.xlsx"
:http-request=
"uploadChangeFile"
:show-file-list=
"false"
>
<
template
#
trigger
>
<el-button
type=
"primary"
>
修改计划上传
</el-button>
</
template
>
</el-upload>
</el-col>
</el-row>
<!-- 表格列表 -->
<el-table
:data=
"tableList"
:cell-style=
"{ 'word-wrap': 'break-word', 'white-space': 'normal' }"
border
style=
"width: 100%"
show-overflow-tooltip
@
selection-change=
"handleSelectionChange"
:row-class-name=
"tableRowTimeOutClassName"
>
<el-table-column
type=
"selection"
width=
"55"
:selectable=
"selectableFn"
>
</el-table-column>
<el-table-column
v-for=
"item in columns"
:key=
"item.label"
:prop=
"item.prop"
:label=
"item.label"
:width=
"item.width"
:formatter=
"formatter"
:fixed=
"item.fixed"
:show-overflow-tooltip=
"true"
/>
<el-table-column
label=
"操作"
width=
"150"
fixed=
"right"
>
<
template
#
default=
"scope"
>
<el-button
type=
"success"
link
:disabled=
"!selectableFn(scope.row)"
@
click=
"editFn(scope.row)"
>
编辑
</el-button>
<el-button
type=
"danger"
link
:disabled=
"!selectableFn(scope.row)"
@
click=
"deletePlane(scope.row)"
>
删除
</el-button>
</
template
>
</el-table-column>
</el-table>
<!-- 分页 -->
<pagination
:total=
"total"
v-model:page=
"queryParams.pageNum"
v-model:limit=
"queryParams.pageSize"
@
pagination=
"getPlanList"
/>
<!-- 弹窗确认上传计划 -->
<el-dialog
title=
"上传计划"
v-model=
"dialogVisible"
:close-on-click-modal=
"false"
:close-on-press-escape=
"false"
width=
"80%"
>
<div>
<!-- 计划表格 -->
<el-table
:data=
"planTableList"
:cell-style=
"{ 'word-wrap': 'break-word', 'white-space': 'normal' }"
border
style=
"width: 100%"
show-overflow-tooltip
:row-class-name=
"tableRowClassName"
>
<el-table-column
v-for=
"item in confirmTableColumns"
:key=
"item.label"
:prop=
"item.prop"
:label=
"item.label"
:width=
"item.width"
:formatter=
"formatterConfirm"
/>
</el-table>
</div>
<
template
#
footer
>
<div
class=
"dialog-footer"
>
<p
style=
"color: red; float: left;"
>
如果表格有红色行,请根据错误提示修改本地表格重新上传
</p>
<el-button
@
click=
"dialogVisible = false"
>
取消上传
</el-button>
<el-button
type=
"primary"
:disabled=
"!confirmExcelUUID"
@
click=
"confirmPlanBtn"
>
确定保存
</el-button>
</div>
</
template
>
</el-dialog>
<!-- 新增/修改计划 -->
<el-dialog
:title=
"(addOrEditPlanForm.id ? '修改' : '新增') + '计划'"
v-model=
"addOrEditPlanVisible"
width=
"60%"
>
<!-- 表单 -->
<el-form
:model=
"addOrEditPlanForm"
label-width=
"150px"
:rules=
"addOrEditPlanFormRules"
ref=
"addOrEditPlanRef"
inline
>
<el-row>
<el-col
:span=
"12"
>
<!-- 选择门店 -->
<el-form-item
label=
"选择门店"
prop=
"storeCode"
>
<el-select
v-model=
"addOrEditPlanForm.storeCode"
placeholder=
"请选择门店"
filterable
clearable
style=
"width: 95%"
@
change=
"selStoreInfo"
remote
:remote-method=
"remoteStoreMethod"
:disabled=
"!!addOrEditPlanForm.id"
>
<el-option
v-for=
"item in storeList"
:key=
"item.value"
:label=
"item.label"
:value=
"item.value"
/>
</el-select>
<p
class=
"info_p"
:class=
"{ info_error: isInfoError }"
>
{{ selecteStoreInfo }}
</p>
<div>
<a
class=
"link"
v-show=
"isInfoError"
target=
"_blank"
href=
"https://cloud.region2.qince.com/sysapp/react/web/main.html#/home"
>
跳转勤策系统
</a>
</div>
</el-form-item>
</el-col>
<el-col
:span=
"12"
>
<!-- 活动日期 -->
<el-form-item
label=
"活动日期"
prop=
"date"
>
<el-date-picker
v-model=
"addOrEditPlanForm.date"
:clearable=
"false"
start-placeholder=
"活动日期"
value-format=
"YYYY-MM-DDTHH:mm:ss"
:disabled-date=
"disabledDateFn"
:disabled=
"!!addOrEditPlanForm.id"
/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<!-- 活动模式 -->
<el-col
:span=
"12"
>
<el-form-item
label=
"活动模式"
prop=
"pattern"
>
<el-select
v-model=
"addOrEditPlanForm.pattern"
placeholder=
"请选择活动模式"
filterable
clearable
style=
"width: 95%"
@
change=
"selPattern"
>
<el-option
v-for=
"item in activityModeList"
:key=
"item.value"
:label=
"item.label"
:value=
"item.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col
:span=
"12"
>
<!-- 归属人 -->
<el-form-item
label=
"归属人"
prop=
"employeeNo"
>
<el-select
v-model=
"addOrEditPlanForm.employeeNo"
placeholder=
"请选择归属人"
filterable
clearable
style=
"width: 95%"
@
change=
"selEmployee"
>
<el-option
v-for=
"item in belongPerList"
:key=
"item.employeeNo"
:label=
"item.label"
:value=
"item.employeeNo"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col
:span=
"12"
>
<!-- 上班打卡时间 -->
<el-form-item
label=
"上班打卡时间"
prop=
"inTime"
>
<el-time-picker
v-model=
"addOrEditPlanForm.inTime"
placeholder=
"选择时间"
format=
"HH:mm"
value-format=
"HH:mm:ss"
style=
"width: 95%"
/>
</el-form-item>
</el-col>
<el-col
:span=
"12"
>
<!-- 下班打卡时间 -->
<el-form-item
label=
"下班打卡时间"
prop=
"outTime"
>
<el-time-picker
v-model=
"addOrEditPlanForm.outTime"
placeholder=
"选择时间"
format=
"HH:mm"
value-format=
"HH:mm:ss"
style=
"width: 95%"
:disabled=
"!addOrEditPlanForm.inTime"
:disabled-hours=
"disabledHours"
:disabled-minutes=
"disabledMinutes"
:disabled-seconds=
"disabledSeconds"
/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col
:span=
"12"
>
<!-- 工资 -->
<el-form-item
label=
"工资"
prop=
"salary"
>
<el-input-number
v-model=
"addOrEditPlanForm.salary"
style=
"width: 80%"
placeholder=
"请输入工资"
/>
</el-form-item>
</el-col>
<el-col
:span=
"12"
>
<!-- 杂费 -->
<el-form-item
label=
"杂费"
prop=
"incidentals"
>
<el-input-number
v-model=
"addOrEditPlanForm.incidentals"
style=
"width: 80%"
placeholder=
"请输入杂费"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
<
template
#
footer
>
<div
class=
"dialog-footer"
>
<el-button
type=
"default"
@
click=
"addOrEditPlanVisible = false"
>
取消
</el-button>
<el-button
type=
"primary"
@
click=
"handleAddOrEditPlan"
:disabled=
"isInfoError"
>
确定保存
</el-button>
</div>
</
template
>
</el-dialog>
<!-- 修改计划归属人 -->
<el-dialog
title=
"修改计划归属人"
v-model=
"editPlanEmpVisible"
width=
"60%"
>
<!-- 表单 -->
<el-form
:model=
"editPlanEmpForm"
label-width=
"150px"
:rules=
"editPlanEmpRules"
ref=
"editPlanEmpRef"
inline
>
<el-form-item
label=
"归属人"
prop=
"employeeId"
>
<el-select
v-model=
"editPlanEmpForm.employeeId"
placeholder=
"请选择归属人(搜索)"
filterable
clearable
>
<el-option
v-for=
"item in belongPerList"
:key=
"item.value"
:label=
"item.label"
:value=
"item.value"
/>
</el-select>
</el-form-item>
</el-form>
<!-- 取消确定 -->
<
template
#
footer
>
<div
class=
"dialog-footer"
>
<el-button
type=
"default"
@
click=
"editPlanEmpVisible = false"
>
取消
</el-button>
<el-button
type=
"primary"
@
click=
"handleEditPlanEmp"
:disabled=
"!editPlanEmpForm.employeeId"
>
确定保存
</el-button>
</div>
</
template
>
</el-dialog>
<el-tabs
type=
"card"
>
<el-tab-pane
label=
"有效计划"
>
<EffectivePlan
ref=
"effectivePlan"
:queryParams=
"queryParams"
/>
</el-tab-pane>
<el-tab-pane
label=
"已删除计划"
>
<InvalidPlan
ref=
"invalidPlan"
:queryParams=
"queryParams"
/>
</el-tab-pane>
</el-tabs>
</div>
</div>
</
template
>
<
script
setup
>
import
{
getPlanListAPI
,
uploadFileToOSSAPI
,
addPlanAPI
,
savePlanAPI
,
deletePlanAPI
,
addPlanByRoleAPI
,
getProCityAPI
,
getDealerListAPI
,
getWarZoneListAPI
,
getChargeListAPI
,
addPlanByWebAPI
,
updatePlanByWebAPI
,
getPlanStoreListAPI
,
updatePlanAPI
,
batchUpdatePlanAPI
}
from
'@/api'
import
{
useDatePickerOptions
,
checkPlanExpire
}
from
'@/hooks'
import
{
v4
as
uuidv4
}
from
'uuid'
;
import
store
from
'@/store'
import
userStore
from
'@/store/modules/user'
import
{
getPromotionActiveStatus
}
from
'@/dicts'
import
{
PROMOTION_STATUS
}
from
'@/dicts'
import
{
getProCityAPI
,
getDealerListAPI
,
getWarZoneListAPI
,
getChargeListAPI
}
from
'@/api'
import
{
parseTime
}
from
'@/utils'
import
{
ElMessage
,
ElMessageBox
}
from
'element-plus'
;
import
userStore
from
'@/store/modules/user'
import
{
useDatePickerOptions
}
from
'@/hooks'
import
{
PROMOTION_STATUS
}
from
'@/dicts'
import
EffectivePlan
from
'./effectivePlan.vue'
import
InvalidPlan
from
'./invalidPlan.vue'
const
{
proxy
}
=
getCurrentInstance
();
const
isCityManager
=
ref
(
userStore
().
promotionIdentity
)
const
{
proxy
}
=
getCurrentInstance
()
const
isCityManager
=
userStore
().
promotionIdentity
const
empInfo
=
userStore
().
empInfo
// 当前登录员工信息
const
{
recentPickerOptions
:
pickerOptions
}
=
useDatePickerOptions
()
const
queryParams
=
reactive
({
activityDate
:
[],
planStatus
:
''
,
region
:
'全国'
,
provinceId
:
''
,
cityId
:
''
,
zone
Id
:
''
,
// 经销商
war
z
oneId
:
''
,
// 战区
dealer
Id
:
''
,
// 经销商
war
Z
oneId
:
''
,
// 战区
employeeId
:
''
,
// 归属人
storeName
:
''
,
// 门店名称
pageNum
:
1
,
pageSize
:
10
,
})
/************* 选择日期 *************/
const
{
recentPickerOptions
:
pickerOptions
}
=
useDatePickerOptions
()
const
selActivityDate
=
()
=>
{
if
(
queryParams
.
activityDate
?.
length
>
0
)
{
queryParams
.
activityDate
=
queryParams
.
activityDate
.
map
(
item
=>
parseTime
(
item
,
'{y}-{m}-{d}'
))
}
getPlanList
()
}
/************* 选择状态 *************/
const
taskStatusList
=
ref
(
Object
.
values
(
PROMOTION_STATUS
))
/
/ 区域查询切换
/
************* 区域查询 *************/
const
provinceList
=
ref
([])
const
cityList
=
ref
([])
// 获取省份和城市列表
const
getProCity
=
async
()
=>
{
const
getProCityList
=
async
()
=>
{
const
{
data
}
=
await
getProCityAPI
(
queryParams
)
// 本次省份里有值,证明 data 是城市数据
if
(
queryParams
.
provinceId
)
{
const
list
=
data
.
map
(
item
=>
({
label
:
item
.
name
,
value
:
item
.
num
}))
queryParams
.
provinceId
?
(
cityList
.
value
=
list
)
:
(
provinceList
.
value
=
list
)
}
getProCityList
()
// 切换省市范围
const
changeRegion
=
async
()
=>
{
if
(
queryParams
.
region
===
'全国'
)
{
queryParams
.
provinceId
=
''
queryParams
.
provinceName
=
''
queryParams
.
cityId
=
''
cityList
.
value
=
data
.
map
(
item
=>
({
label
:
item
.
name
,
value
:
item
.
num
}))
}
else
{
// 省份列表数据
queryParams
.
cityName
=
''
}
else
if
(
queryParams
.
region
===
'省'
)
{
queryParams
.
cityId
=
''
cityList
.
value
=
[]
provinceList
.
value
=
data
.
map
(
item
=>
({
label
:
item
.
name
,
value
:
item
.
num
}))
queryParams
.
cityName
=
''
}
getPlanList
()
}
// 切换
const
regionChange
=
(
val
)
=>
{
if
(
val
===
'全国'
)
{
queryParams
.
provinceId
=
''
queryParams
.
cityId
=
''
}
else
if
(
val
===
'省'
)
{
queryParams
.
cityId
=
''
}
else
if
(
val
===
'省-市'
)
{
cityList
.
value
=
[]
getProCity
()
}
// 选择省
const
selProvince
=
async
()
=>
{
// 设置省名
queryParams
.
provinceName
=
provinceList
.
value
.
find
(
item
=>
item
.
value
===
queryParams
.
provinceId
)?.
label
// 重置城市
queryParams
.
cityId
=
''
queryParams
.
cityName
=
''
cityList
.
value
=
[]
// 重新获取城市列表以及查询列表
getProCityList
()
getPlanList
()
}
// 选择市
const
selCity
=
async
()
=>
{
// 设置市名
queryParams
.
cityName
=
cityList
.
value
.
find
(
item
=>
item
.
value
===
queryParams
.
cityId
)?.
label
// 重新获取查询列表
getPlanList
()
}
/
/ 查询经销商列表
const
zone
List
=
ref
([])
const
get
Zone
List
=
async
()
=>
{
/
*************** 经销商 ***************/
const
dealer
List
=
ref
([])
const
get
Dealer
List
=
async
()
=>
{
const
{
data
}
=
await
getDealerListAPI
(
queryParams
)
zone
List
.
value
=
data
.
map
(
item
=>
{
dealer
List
.
value
=
data
.
map
(
item
=>
{
return
{
label
:
item
.
dealerName
,
value
:
item
.
dealerId
}
})
}
// 经销商远程搜索
(点击输入框自动触发)
const
zoneRemoteSearch
=
(
quer
y
)
=>
{
queryParams
.
dealerName
=
quer
y
get
Zone
List
()
// 经销商远程搜索
const
dealerRemoteSearch
=
(
searchKe
y
)
=>
{
queryParams
.
dealerName
=
searchKe
y
get
Dealer
List
()
}
/
/ 查询战区列表
/
*************** 战区 ***************/
const
warZoneList
=
ref
([])
const
getWarZoneList
=
async
()
=>
{
const
{
data
}
=
await
getWarZoneListAPI
()
...
...
@@ -544,9 +250,11 @@ const getWarZoneList = async () => {
value
:
item
.
qcId
}
})
// 城市经理,设置默认战区
isCityManager
&&
(
queryParams
.
warZoneId
=
belongPerList
.
value
.
find
(
item
=>
item
.
employeeNo
===
empInfo
.
empNo
)?.
deptQcId
)
}
/
/ 查询归属人列表
/
*************** 归属人 ***************/
const
belongPerList
=
ref
([])
const
getBelongPerList
=
async
()
=>
{
const
{
data
}
=
await
getChargeListAPI
()
...
...
@@ -559,747 +267,20 @@ const getBelongPerList = async () => {
deptQcId
:
item
.
deptQcId
}
})
}
// 表格复选框的数据
const
checkedRowList
=
ref
([])
// 同时删除多行的按钮禁用状态
const
delMultipleBtnDis
=
ref
(
true
)
// 同时修改多行的归属人禁用状态
const
editMultipleBtnDis
=
ref
(
true
)
// 表格全选复选框点击
const
handleSelectionChange
=
(
val
)
=>
{
checkedRowList
.
value
=
val
delMultipleBtnDis
.
value
=
!
(
checkedRowList
.
value
.
length
>
0
)
editMultipleBtnDis
.
value
=
!
(
checkedRowList
.
value
.
length
>
0
)
// 判断如果勾选了活动日期不是当月的,删除按钮也得被禁用
// if (checkedRowList.value.length > 0) {
// const isSameMonth = checkedRowList.value.every(item => {
// const date = new Date(item.date)
// const year = date.getFullYear()
// const month = date.getMonth() + 1
// const currentDate = new Date()
// const currentYear = currentDate.getFullYear()
// const currentMonth = currentDate.getMonth() + 1
// return year === currentYear && month === currentMonth
// })
// delMultipleBtnDis.value = !isSameMonth
// }
// 城市经理,设置默认归属人
isCityManager
&&
(
queryParams
.
employeeId
=
belongPerList
.
value
.
find
(
item
=>
item
.
employeeNo
===
empInfo
.
empNo
)?.
value
)
}
// 任务列表
const
tableList
=
ref
([])
const
total
=
ref
(
0
)
const
columns
=
ref
([
{
label
:
'归属人'
,
prop
:
'employeeName'
,
width
:
150
,
fixed
:
true
},
{
label
:
'战区'
,
prop
:
'orgName'
,
width
:
120
},
{
label
:
'店铺名称'
,
prop
:
'storeName'
,
width
:
240
},
{
label
:
'活动日期'
,
prop
:
'date'
,
width
:
120
},
{
label
:
'星期'
,
prop
:
'week'
,
width
:
80
},
{
label
:
'活动状态'
,
prop
:
'planStatus'
,
width
:
100
},
{
label
:
'活动模式'
,
prop
:
'pattern'
,
width
:
100
},
{
label
:
'系统名称'
,
prop
:
'lineName'
,
width
:
150
},
{
label
:
'店铺编码'
,
prop
:
'storeCode'
,
width
:
160
},
{
label
:
'经销商'
,
prop
:
'dealerName'
,
width
:
220
},
{
label
:
'经销商 ID'
,
prop
:
'dealerId'
,
width
:
120
},
{
label
:
'省份'
,
prop
:
'province'
,
width
:
100
},
{
label
:
'地址'
,
prop
:
'addr'
,
width
:
200
},
{
label
:
'上班时间'
,
prop
:
'clockInTime'
,
width
:
180
},
{
label
:
'下班时间'
,
prop
:
'clockOutTime'
,
width
:
180
},
{
label
:
'促销员薪资'
,
prop
:
'salary'
,
width
:
100
},
{
label
:
'杂费'
,
prop
:
'incidentals'
,
width
:
100
},
{
label
:
'创建人'
,
prop
:
'createBy'
,
width
:
120
},
{
label
:
'最近修改人'
,
prop
:
'modifyBy'
,
width
:
100
},
{
label
:
'最后修改时间'
,
prop
:
'modifyTime'
,
width
:
180
},
{
label
:
'活动 ID'
,
prop
:
'id'
,
width
:
90
}
])
const
getPlanList
=
async
()
=>
{
// 后台:省市不要 id,查个名字给后台(但是省市区接口还得用 id,所以 queryParams 上还必须绑定 id)
queryParams
.
province
=
provinceList
.
value
.
find
(
item
=>
item
.
value
===
queryParams
.
provinceId
)?.
label
queryParams
.
city
=
cityList
.
value
.
find
(
item
=>
item
.
value
===
queryParams
.
cityId
)?.
label
// 城市经理查自己,职能角色查所有
if
(
isCityManager
.
value
)
{
// 城市经理 (用员工 ID(1,2,3),而不是工号,employeeNo 是工号(000535))
queryParams
.
employeeId
=
belongPerList
.
value
.
find
(
item
=>
item
.
employeeNo
===
userStore
().
employeeNo
)?.
value
// 先从归属人查询当前登录用户的战区 ID
queryParams
.
warzoneId
=
belongPerList
.
value
.
find
(
item
=>
item
.
employeeNo
===
userStore
().
employeeNo
)?.
deptQcId
}
// 日期格式化一下
if
(
queryParams
.
activityDate
?.
length
>
0
)
{
queryParams
.
activityDate
=
queryParams
.
activityDate
.
map
(
item
=>
parseTime
(
item
,
'{y}-{m}-{d}'
))
}
const
res
=
await
getPlanListAPI
({
pageNum
:
queryParams
.
pageNum
,
pageSize
:
queryParams
.
pageSize
,
queryParams
:
{
activityStartDate
:
queryParams
.
activityDate
&&
queryParams
.
activityDate
[
0
],
activityEndDate
:
queryParams
.
activityDate
&&
queryParams
.
activityDate
[
1
],
planStatus
:
queryParams
.
planStatus
,
region
:
queryParams
.
region
,
province
:
queryParams
.
province
,
city
:
queryParams
.
city
,
dealerId
:
queryParams
.
zoneId
,
orgQcId
:
queryParams
.
warzoneId
,
employeeId
:
queryParams
.
employeeId
,
storeNameLike
:
queryParams
.
storeName
}
})
tableList
.
value
=
res
.
data
.
records
total
.
value
=
res
.
data
.
totalRecord
}
// 格式化计划列表单元格内容
const
formatter
=
(
row
,
col
,
value
)
=>
{
if
(
col
.
property
===
'planStatus'
)
{
return
getPromotionActiveStatus
(
value
)?.
label
}
else
if
(
col
.
property
===
'date'
)
{
// 活动日期
return
parseTime
(
value
,
'{y}-{m}-{d}'
)
}
else
if
(
col
.
property
===
'week'
)
{
return
parseTime
(
row
[
'date'
],
'周{a}'
)
}
else
if
(
col
.
property
===
'modifyTime'
)
{
return
parseTime
(
value
,
'{y}-{m}-{d} {h}:{i}:{s}'
)
}
else
if
(
col
.
property
===
'clockInTime'
||
col
.
property
===
'clockOutTime'
)
{
return
parseTime
(
value
)
}
else
if
(
col
.
property
===
'employeeName'
)
{
// 判断归属人名字小于 4 个字,少于几个就加几个空格
if
(
value
.
length
===
2
)
{
return
value
+
' '
+
'('
+
row
.
employeeNo
+
')'
}
else
if
(
value
.
length
===
3
)
{
return
value
+
' '
+
'('
+
row
.
employeeNo
+
')'
}
else
{
return
value
+
'('
+
row
.
employeeNo
+
')'
}
}
else
if
(
col
.
property
===
'salary'
||
col
.
property
===
'incidentals'
)
{
return
'¥ '
+
value
+
' 元'
}
else
{
return
value
}
}
// 计划是否可选和编辑和删除按钮禁用
const
selectableFn
=
(
row
)
=>
{
return
checkPlanExpire
(
row
)
}
// 计划是否已经过期,不可以操作(返回灰色行样式)
const
tableRowTimeOutClassName
=
({
row
})
=>
{
const
isExpire
=
checkPlanExpire
(
row
)
if
(
!
isExpire
)
{
return
'timeout-row'
}
else
{
return
''
}
}
// 批量修改归属人
const
editPlanEmpVisible
=
ref
(
false
)
const
editPlanEmpForm
=
ref
({
employeeId
:
null
})
const
editPlanEmpRules
=
ref
({
employeeId
:
[{
required
:
true
,
message
:
'请选择归属人'
,
trigger
:
'change'
}]
})
// 点击修改归属人按钮
const
handleEditEmp
=
()
=>
{
editPlanEmpVisible
.
value
=
true
nextTick
(()
=>
{
editPlanEmpForm
.
value
.
employeeId
=
null
proxy
.
resetForm
(
"editPlanEmpRef"
);
})
}
// 确定批量修改计划人
const
handleEditPlanEmp
=
async
()
=>
{
const
res
=
await
batchUpdatePlanAPI
({
employeeId
:
editPlanEmpForm
.
value
.
employeeId
,
operName
:
store
.
state
.
value
.
user
.
userInfo
.
nickName
,
planIds
:
checkedRowList
.
value
.
map
(
item
=>
item
.
id
)
})
ElMessage
.
success
(
res
.
msg
)
editPlanEmpVisible
.
value
=
false
getPlanList
()
}
// 上传计划表格
const
uploadFile
=
async
(
file
)
=>
{
proxy
.
$modal
.
loading
(
"正在上传数据,请稍后..."
);
// 拼接当前月数为文件夹名
const
date
=
new
Date
()
const
month
=
date
.
getMonth
()
+
1
const
excelUrl
=
await
uploadFileToOSSAPI
(
`planExcel/
${
date
.
getFullYear
()}
-
${
month
}
/
${
userStore
().
employeeNo
}
/
${
uuidv4
()}
.xlsx`
,
file
.
file
)
const
targetAPI
=
isCityManager
.
value
?
addPlanAPI
:
addPlanByRoleAPI
try
{
const
res
=
await
targetAPI
({
"excelUrl"
:
excelUrl
,
"employeeNo"
:
userStore
().
employeeNo
})
planTableList
.
value
=
res
.
data
.
table
confirmExcelUUID
.
value
=
res
.
data
.
uuid
dialogVisible
.
value
=
true
proxy
.
$modal
.
closeLoading
();
}
catch
(
err
)
{
proxy
.
$modal
.
closeLoading
();
}
return
true
}
// 确认计划
const
planTableList
=
ref
([])
const
dialogVisible
=
ref
(
false
)
const
confirmExcelUUID
=
ref
(
''
)
const
confirmTableColumns
=
[
{
label
:
'错误消息'
,
prop
:
'errorMsg'
,
width
:
450
},
{
label
:
'归属人'
,
prop
:
'employeeName'
,
width
:
90
,
fixed
:
true
},
{
label
:
'归属人工号'
,
prop
:
'employeeNo'
,
width
:
140
},
{
label
:
'店铺名称'
,
prop
:
'storeName'
,
width
:
200
},
{
label
:
'店铺编码'
,
prop
:
'storeCode'
,
width
:
160
},
{
label
:
'活动模式'
,
prop
:
'pattern'
,
width
:
100
},
{
label
:
'活动日期'
,
prop
:
'date'
,
width
:
180
},
{
label
:
'上班时间'
,
prop
:
'clockInTime'
,
width
:
180
},
{
label
:
'下班时间'
,
prop
:
'clockOutTime'
,
width
:
180
},
{
label
:
'促销员薪资'
,
prop
:
'salary'
,
width
:
100
},
{
label
:
'杂费'
,
prop
:
'incidentals'
,
width
:
100
},
// {
// label: '活动 ID',
// prop: 'id',
// width: 90,
// // fixed: true
// },
{
label
:
'经销商 ID'
,
prop
:
'dealerId'
,
width
:
120
},
{
label
:
'经销商'
,
prop
:
'dealerName'
,
width
:
220
},
{
label
:
'系统名称'
,
prop
:
'lineName'
,
width
:
100
},
// {
// label: '活动状态',
// prop: 'planStatus',
// width: 100
// },
{
label
:
'省份'
,
prop
:
'province'
,
width
:
100
},
{
label
:
'地址'
,
prop
:
'addr'
,
width
:
200
},
{
label
:
'战区'
,
prop
:
'orgName'
,
width
:
150
},
// {
// label: '城市',
// prop: 'city',
// width: 100
// },
{
label
:
'创建人'
,
prop
:
'createBy'
,
width
:
100
},
{
label
:
'最近修改人'
,
prop
:
'modifyBy'
,
width
:
100
},
{
label
:
'最后修改时间'
,
prop
:
'modifyTime'
,
width
:
250
}
]
const
tableRowClassName
=
({
row
})
=>
{
if
(
row
.
errorMsg
)
{
return
'error-row'
}
else
{
return
''
}
}
const
formatterConfirm
=
(
row
,
col
,
value
)
=>
{
if
(
col
.
property
===
'clockInTime'
||
col
.
property
===
'clockOutTime'
||
col
.
property
===
'date'
)
{
return
parseTime
(
value
)
}
else
if
(
col
.
property
===
'errorMsg'
)
{
// 把分号替换成 \n
return
value
&&
value
.
replace
(
/;/g
,
'
\
n'
)
}
else
{
return
value
}
}
const
addOrEditPlanRef
=
ref
(
null
)
// 表格上传计划确认保存
const
confirmPlanBtn
=
async
()
=>
{
await
savePlanAPI
(
confirmExcelUUID
.
value
)
ElMessage
.
success
(
'保存成功'
)
dialogVisible
.
value
=
false
getPlanList
()
}
// 新增/编辑计划表单弹框
const
addOrEditPlanVisible
=
ref
(
false
)
const
addOrEditPlanForm
=
ref
({})
// 重置表单
const
resetAddOrEditPlanForm
=
()
=>
{
addOrEditPlanForm
.
value
=
{}
selecteStoreInfo
.
value
=
''
isInfoError
.
value
=
false
}
// 表单验证(所有都是必填项)
const
addOrEditPlanFormRules
=
reactive
({
storeCode
:
[
{
required
:
true
,
message
:
'请输入门店编码'
,
trigger
:
'blur'
}
],
date
:
[
{
required
:
true
,
message
:
'请选择活动日期'
,
trigger
:
'blur'
}
],
pattern
:
[
{
required
:
true
,
message
:
'请选择活动模式'
,
trigger
:
'blur'
}
],
employeeNo
:
[
{
required
:
true
,
message
:
'请选择归属人'
,
trigger
:
'blur'
}
],
inTime
:
[
{
required
:
true
,
message
:
'请选择上班打卡时间'
,
trigger
:
'blur'
}
],
outTime
:
[
{
required
:
true
,
message
:
'请选择下班打卡时间'
,
trigger
:
'blur'
}
],
salary
:
[
{
required
:
true
,
message
:
'请输入工资'
,
trigger
:
'blur'
}
],
incidentals
:
[
{
required
:
true
,
message
:
'请输入杂费'
,
trigger
:
'blur'
}
]
})
// 定义禁用日期的函数
const
disabledDateFn
=
(
time
)
=>
{
// 城市经理只能新增下个月一整个月的
if
(
isCityManager
.
value
)
{
const
now
=
new
Date
();
const
start
=
new
Date
(
now
.
getFullYear
(),
now
.
getMonth
()
+
1
,
1
);
const
end
=
new
Date
(
now
.
getFullYear
(),
now
.
getMonth
()
+
2
,
0
);
return
time
.
getTime
()
<
start
.
getTime
()
||
time
.
getTime
()
>
end
.
getTime
()
}
else
{
// 职能角色能添加当月今天往后和下个月一整个月
const
now
=
new
Date
();
const
thisMonthStart
=
new
Date
(
now
.
getFullYear
(),
now
.
getMonth
(),
now
.
getDate
());
const
nextMonthEnd
=
new
Date
(
now
.
getFullYear
(),
now
.
getMonth
()
+
2
,
0
);
return
time
.
getTime
()
<
thisMonthStart
.
getTime
()
||
time
.
getTime
()
>
nextMonthEnd
.
getTime
();
}
}
const
handleAdd
=
()
=>
{
resetAddOrEditPlanForm
()
// 只有城市经理情况下,默认填充当前登录人为归属人
if
(
isCityManager
.
value
)
{
addOrEditPlanForm
.
value
.
employeeNo
=
userStore
().
employeeNo
}
addOrEditPlanVisible
.
value
=
true
}
const
activityModeList
=
ref
([
{
label
:
'单点CP'
,
value
:
'单点CP'
},
{
label
:
'常规MINI秀'
,
value
:
'常规MINI秀'
},
{
label
:
'校园活动'
,
value
:
'校园活动'
}
])
// 根据选择的开始时间,禁用小时分钟秒只能选择之后的时间
const
makeRange
=
(
start
,
end
)
=>
{
const
result
=
[]
for
(
let
i
=
start
;
i
<=
end
;
i
++
)
{
result
.
push
(
i
)
}
return
result
}
const
disabledHours
=
(
h
)
=>
{
// 根据上班时间选择的结果,禁用小时
const
date
=
new
Date
(
addOrEditPlanForm
.
value
.
nTime
)
return
makeRange
(
0
,
date
.
getHours
()
-
1
);
}
const
disabledMinutes
=
(
h
,
m
)
=>
{
// 如果小时大于上班打卡时间小时,则不限制分钟
const
inDate
=
new
Date
(
addOrEditPlanForm
.
value
.
inTime
)
if
(
h
>
inDate
.
getHours
())
{
return
makeRange
(
0
,
-
1
);
}
else
{
const
date
=
new
Date
(
addOrEditPlanForm
.
value
.
inTime
)
return
makeRange
(
0
,
date
.
getMinutes
()
-
1
);
}
}
const
disabledSeconds
=
(
h
,
m
,
s
)
=>
{
const
date
=
new
Date
(
addOrEditPlanForm
.
value
.
inTime
)
return
makeRange
(
0
,
date
.
getSeconds
()
-
1
);
}
// 开始编辑某行计划
const
editFn
=
(
row
)
=>
{
addOrEditPlanForm
.
value
=
{
...
row
,
inTime
:
parseTime
(
row
.
clockInTime
,
"{h}:{i}:{s}"
),
outTime
:
parseTime
(
row
.
clockOutTime
,
"{h}:{i}:{s}"
)
}
addOrEditPlanVisible
.
value
=
true
}
// 保存新增/编辑计划
const
handleAddOrEditPlan
=
async
()
=>
{
// 表单校验
await
addOrEditPlanRef
.
value
.
validate
()
addOrEditPlanForm
.
value
.
operNo
=
userStore
().
employeeNo
addOrEditPlanForm
.
value
.
operName
=
store
.
state
.
value
.
user
.
userInfo
.
nickName
addOrEditPlanForm
.
value
.
operId
=
store
.
state
.
value
.
user
.
userInfo
.
userId
const
dataObj
=
{
...
addOrEditPlanForm
.
value
,
// 格式是 xx:xx:xx,替换最后一对 xx 为 00
inTime
:
addOrEditPlanForm
.
value
.
inTime
.
replace
(
/:
\d{2}
$/
,
':00'
),
outTime
:
addOrEditPlanForm
.
value
.
outTime
.
replace
(
/:
\d{2}
$/
,
':00'
)
}
if
(
dataObj
.
id
)
{
// 根据归属人 employeeId 查询它的 id 和名字
const
employeeInfo
=
belongPerList
.
value
.
find
(
item
=>
item
.
employeeNo
===
dataObj
.
employeeNo
)
dataObj
.
employeeId
=
employeeInfo
.
value
dataObj
.
employeeName
=
employeeInfo
.
label
await
updatePlanByWebAPI
(
dataObj
)
}
else
{
await
addPlanByWebAPI
(
dataObj
)
}
ElMessage
.
success
(
'保存成功'
)
addOrEditPlanVisible
.
value
=
false
getPlanList
()
}
// 删除计划
const
deletePlane
=
(
row
)
=>
{
checkedRowList
.
value
=
[
row
]
handleDelete
()
}
const
handleDelete
=
async
()
=>
{
// 弹出确认框
await
ElMessageBox
.
confirm
(
'确认删除吗?'
,
'提示'
,
{
confirmButtonText
:
'确定'
,
cancelButtonText
:
'取消'
,
type
:
'warning'
})
await
deletePlanAPI
({
planIds
:
checkedRowList
.
value
.
map
(
o
=>
o
.
id
),
employeeNo
:
userStore
().
employeeNo
})
ElMessage
.
success
(
'删除成功'
)
getPlanList
()
}
// 获取门店列表
const
storeList
=
ref
([])
const
allStoreList
=
ref
([])
const
selecteStoreInfo
=
ref
(
''
)
const
isInfoError
=
ref
(
false
)
const
getStoreList
=
async
()
=>
{
const
{
data
}
=
await
getPlanStoreListAPI
({
storeName
:
addOrEditPlanForm
.
value
.
storeName
})
allStoreList
.
value
=
data
storeList
.
value
=
data
.
map
(
item
=>
{
return
{
label
:
item
.
storeName
,
value
:
item
.
storeCode
}
})
}
getStoreList
()
// 选择门店
const
selStoreInfo
=
(
storeCode
)
=>
{
// 从门店列表找到选中的对象
const
storeInfo
=
allStoreList
.
value
.
find
(
item
=>
item
.
storeCode
===
storeCode
)
// 判断门店是否包含必要的三个信息(因为勤测那边的数据一致性不好,所以需要判断)
if
(
storeInfo
)
{
if
(
!
storeInfo
.
dealersName
||
!
storeInfo
.
dealerId
||
!
storeInfo
.
lineName
)
{
isInfoError
.
value
=
true
// 门店系统名称、经销商不可为空,请到勤策中修改;
selecteStoreInfo
.
value
=
"门店系统名称、经销商不可为空,请到勤策中修改:"
}
else
{
isInfoError
.
value
=
false
// 门店系统名称、经销商不可为空,请到勤策中修改;
selecteStoreInfo
.
value
=
storeInfo
.
storeAddr
+
"-"
+
storeInfo
.
storeCode
}
}
else
{
isInfoError
.
value
=
false
// 门店系统名称、经销商不可为空,请到勤策中修改;
selecteStoreInfo
.
value
=
''
}
// 清除表单验证提示
addOrEditPlanRef
.
value
.
clearValidate
(
'storeCode'
);
}
// 门店搜索
const
remoteStoreMethod
=
(
query
)
=>
{
addOrEditPlanForm
.
value
.
storeName
=
query
getStoreList
()
}
// 新增计划表单-选完以后去掉错误提示
const
selPattern
=
()
=>
{
addOrEditPlanRef
.
value
.
clearValidate
(
'pattern'
);
}
const
selEmployee
=
()
=>
{
addOrEditPlanRef
.
value
.
clearValidate
(
'employeeNo'
);
}
// 批量表格修改计划
const
uploadChangeFile
=
async
(
file
)
=>
{
proxy
.
$modal
.
loading
(
"正在上传数据,请稍后..."
);
// 拼接当前月数为文件夹名
const
date
=
new
Date
()
const
month
=
date
.
getMonth
()
+
1
const
excelUrl
=
await
uploadFileToOSSAPI
(
`planExcel/
${
date
.
getFullYear
()}
-
${
month
}
/
${
userStore
().
employeeNo
}
/
${
uuidv4
()}
.xlsx`
,
file
.
file
)
const
res
=
await
updatePlanAPI
({
"excelUrl"
:
excelUrl
,
"employeeNo"
:
userStore
().
employeeNo
})
planTableList
.
value
=
res
.
data
.
table
confirmExcelUUID
.
value
=
res
.
data
.
uuid
dialogVisible
.
value
=
true
proxy
.
$modal
.
closeLoading
();
return
true
}
const
init
=
async
()
=>
{
onMounted
(
async
()
=>
{
// 给城市经理设置默认选中战区,需要确保归属人列表数据有值
await
getBelongPerList
()
getPlanList
()
// 任务列表需要当前归属人 id,所以保证上一步网络请求完成
getProCity
()
getWarZoneList
()
})
};
init
()
</
script
>
<
style
scoped
lang=
"scss"
>
.el-table
{
::v-deep
(
.error-row
)
{
--el-table-tr-bg-color
:
var
(
--
el-color-error-light-9
);
}
/* 灰色过期行颜色 */
::v-deep
(
.timeout-row
)
{
--el-table-tr-bg-color
:
var
(
--
el-timeout-row
);
}
}
.upload-demo
{
display
:
inline-block
;
margin
:
0
5px
;
}
/* 门店列表选择后-下面的介绍信息 */
.info_p
{
margin
:
0
;
font-size
:
12px
;
color
:
gray
;
}
.info_error
{
color
:
rgb
(
167
,
0
,
0
);
}
.link
{
color
:
#409eff
;
}
.
container
.
el-table
:
:
v-deep
(
.
cell
)
{
/* white-space: pre-line; */
/* 强制显示 2 行,超出的省略号 */
/* overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical; */
}
</
style
>
\ No newline at end of file
/************ 数据列表管理 ************/
const
getPlanList
=
()
=>
{
proxy
.
$refs
.
effectivePlan
.
getPlanList
(
'resetPage'
)
proxy
.
$refs
.
invalidPlan
.
getPlanList
(
'resetPage'
)
}
</
script
>
\ No newline at end of file
src/views/promotion/plan/invalidPlan.vue
0 → 100644
浏览文件 @
13773395
<
template
>
<!-- 表格列表 -->
<el-table
:data=
"tableList"
border
style=
"width: 100%"
show-overflow-tooltip
:row-class-name=
"tableRowTimeOutClassName"
>
<!--
<el-table-column
type=
"selection"
width=
"55"
:selectable=
"selectableFn"
>
</el-table-column>
-->
<el-table-column
v-for=
"item in columns"
:key=
"item.label"
:prop=
"item.prop"
:label=
"item.label"
:width=
"item.width"
:formatter=
"formatter"
:fixed=
"item.fixed"
:show-overflow-tooltip=
"true"
/>
<!--
<el-table-column
label=
"操作"
width=
"150"
fixed=
"right"
>
<template
#
default=
"scope"
>
<el-button
type=
"success"
link
:disabled=
"!selectableFn(scope.row)"
@
click=
"editFn(scope.row)"
>
编辑
</el-button>
<el-button
type=
"danger"
link
:disabled=
"!selectableFn(scope.row)"
@
click=
"deletePlane(scope.row)"
>
删除
</el-button>
</
template
>
</el-table-column>
-->
</el-table>
<!-- 分页 -->
<pagination
:total=
"total"
v-model:page=
"pageNum"
v-model:limit=
"pageSize"
@
pagination=
"getPlanList"
/>
</template>
<
script
setup
>
import
{
getPlanListAPI
}
from
'@/api'
import
{
getPromotionActiveStatus
}
from
'@/dicts'
import
{
parseTime
}
from
'@/utils'
const
{
proxy
}
=
getCurrentInstance
();
const
props
=
defineProps
({
queryParams
:
{
type
:
Object
,
}
})
/*************** 计划表格 ***************/
const
tableList
=
ref
([])
const
columns
=
ref
([
{
label
:
'归属人'
,
prop
:
'employeeName'
,
width
:
150
,
fixed
:
true
},
{
label
:
'战区'
,
prop
:
'orgName'
,
width
:
120
},
{
label
:
'店铺名称'
,
prop
:
'storeName'
,
width
:
240
},
{
label
:
'活动日期'
,
prop
:
'date'
,
width
:
120
},
{
label
:
'星期'
,
prop
:
'week'
,
width
:
80
},
{
label
:
'活动状态'
,
prop
:
'planStatus'
,
width
:
100
},
{
label
:
'活动模式'
,
prop
:
'pattern'
,
width
:
100
},
{
label
:
'系统名称'
,
prop
:
'lineName'
,
width
:
150
},
{
label
:
'店铺编码'
,
prop
:
'storeCode'
,
width
:
160
},
{
label
:
'经销商'
,
prop
:
'dealerName'
,
width
:
220
},
{
label
:
'经销商 ID'
,
prop
:
'dealerId'
,
width
:
120
},
{
label
:
'省份'
,
prop
:
'province'
,
width
:
100
},
{
label
:
'地址'
,
prop
:
'addr'
,
width
:
200
},
{
label
:
'上班时间'
,
prop
:
'clockInTime'
,
width
:
180
},
{
label
:
'下班时间'
,
prop
:
'clockOutTime'
,
width
:
180
},
{
label
:
'促销员薪资'
,
prop
:
'salary'
,
width
:
100
},
{
label
:
'杂费'
,
prop
:
'incidentals'
,
width
:
100
},
{
label
:
'创建人'
,
prop
:
'createBy'
,
width
:
120
},
{
label
:
'最近修改人'
,
prop
:
'modifyBy'
,
width
:
100
},
{
label
:
'最后修改时间'
,
prop
:
'modifyTime'
,
width
:
180
},
{
label
:
'活动 ID'
,
prop
:
'id'
,
width
:
90
}
])
// 格式化计划列表单元格内容
const
formatter
=
(
row
,
col
,
value
)
=>
{
if
(
col
.
property
===
'planStatus'
)
{
return
getPromotionActiveStatus
(
value
)?.
label
}
else
if
(
col
.
property
===
'date'
)
{
// 活动日期
return
parseTime
(
value
,
'{y}-{m}-{d}'
)
}
else
if
(
col
.
property
===
'week'
)
{
return
parseTime
(
row
[
'date'
],
'周{a}'
)
}
else
if
(
col
.
property
===
'modifyTime'
)
{
return
parseTime
(
value
,
'{y}-{m}-{d} {h}:{i}:{s}'
)
}
else
if
(
col
.
property
===
'clockInTime'
||
col
.
property
===
'clockOutTime'
)
{
return
parseTime
(
value
)
}
else
if
(
col
.
property
===
'employeeName'
)
{
// 判断归属人名字小于 4 个字,少于几个就加几个空格
if
(
value
.
length
===
2
)
{
return
value
+
' '
+
'('
+
row
.
employeeNo
+
')'
}
else
if
(
value
.
length
===
3
)
{
return
value
+
' '
+
'('
+
row
.
employeeNo
+
')'
}
else
{
return
value
+
'('
+
row
.
employeeNo
+
')'
}
}
else
if
(
col
.
property
===
'salary'
||
col
.
property
===
'incidentals'
)
{
return
'¥ '
+
value
+
' 元'
}
else
{
return
value
}
}
// 计算当前行类名
const
tableRowTimeOutClassName
=
()
=>
{
// 检查计划是否能操作
return
'timeout-row'
}
/*************** 数据和分页 ***************/
const
total
=
ref
(
0
)
const
pageNum
=
ref
(
1
)
const
pageSize
=
ref
(
10
)
// 任务列表
const
getPlanList
=
async
(
arg
)
=>
{
if
(
arg
===
'resetPage'
)
pageNum
.
value
=
1
const
res
=
await
getPlanListAPI
({
pageNum
:
pageNum
.
value
,
pageSize
:
pageSize
.
value
,
queryParams
:
{
activityStartDate
:
props
.
queryParams
.
activityDate
&&
props
.
queryParams
.
activityDate
[
0
],
activityEndDate
:
props
.
queryParams
.
activityDate
&&
props
.
queryParams
.
activityDate
[
1
],
planStatus
:
props
.
queryParams
.
planStatus
,
region
:
props
.
queryParams
.
region
,
province
:
props
.
queryParams
.
provinceName
,
city
:
props
.
queryParams
.
cityName
,
dealerId
:
props
.
queryParams
.
dealerId
,
orgQcId
:
props
.
queryParams
.
warZoneId
,
employeeId
:
props
.
queryParams
.
employeeId
,
storeNameLike
:
props
.
queryParams
.
storeName
,
statusType
:
'INVALID'
// 查询已删除的计划
}
})
tableList
.
value
=
res
.
data
.
records
total
.
value
=
res
.
data
.
totalRecord
}
getPlanList
()
defineExpose
({
getPlanList
})
onMounted
(()
=>
{
// 删除任务时,重新请求已删除列表
proxy
.
eventBus
.
on
(
'refreshPlanList'
,
getPlanList
)
})
onUnmounted
(()
=>
{
proxy
.
eventBus
.
off
(
'refreshPlanList'
,
getPlanList
)
})
</
script
>
<
style
scoped
lang=
"scss"
>
.el-table
{
/* 灰色过期行颜色 */
::v-deep
(
.timeout-row
)
{
--el-table-tr-bg-color
:
var
(
--
el-timeout-row
);
}
}
</
style
>
\ No newline at end of file
src/views/promotion/task/index.vue
浏览文件 @
13773395
...
...
@@ -70,6 +70,7 @@
<el-select
v-model=
"queryParams.zoneId"
placeholder=
"请选择战区"
clearable
filterable
:disabled=
"cityManagerPrivilege"
@
change=
"getTaskList"
>
<el-option
v-for=
"item in zoneList"
...
...
@@ -84,6 +85,7 @@
placeholder=
"请选择负责人"
:disabled=
"cityManagerPrivilege"
clearable
filterable
@
change=
"getTaskList"
>
<el-option
v-for=
"item in managerList"
:key=
"item.value"
...
...
@@ -91,7 +93,7 @@
:value=
"item.value"
/>
</el-select>
</el-form-item>
<el-form-item
label=
"
门店
"
<el-form-item
label=
"
店铺名
"
prop=
"store"
>
<el-input
v-model=
"queryParams.storeName"
clearable
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论