Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
W
wangxiaolu-sfa-ui
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
sfa
wangxiaolu-sfa-ui
Commits
afb35335
提交
afb35335
authored
2月 18, 2025
作者:
lidongxu
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
feat(promotion): 促销新增单条完成
同上
上级
9a6da717
显示空白字符变更
内嵌
并排
正在显示
4 个修改的文件
包含
526 行增加
和
29 行删除
+526
-29
.env.staging
.env.staging
+1
-1
plan.js
src/api/promotion/plan.js
+31
-5
task.js
src/api/promotion/task.js
+1
-1
index.vue
src/views/promotion/plan/index.vue
+493
-22
没有找到文件。
.env.staging
浏览文件 @
afb35335
...
...
@@ -3,7 +3,7 @@ VITE_APP_TITLE = 王小卤-链路中心
# 基地址
VITE_APP_BASE_API = '/api'
VITE_APP_PROMOTION = '
/promotion-api
' # 促销
VITE_APP_PROMOTION = '
http://promotion.wxl66.cn:8010/
' # 促销
# 开发环境配置
VITE_APP_ENV = 'staging'
...
...
src/api/promotion/plan.js
浏览文件 @
afb35335
...
...
@@ -8,11 +8,18 @@ export function getPlanListAPI(queryParams) {
url
:
'/plan/v2/query/page'
,
method
:
'POST'
,
data
:
{
"pageNum"
:
queryParams
.
pageNum
,
"pageSize"
:
queryParams
.
pageSize
,
"queryParams"
:
{
"activityStartDate"
:
queryParams
.
activityDate
[
0
],
"activityEndDate"
:
queryParams
.
activityDate
[
1
]
pageNum
:
queryParams
.
pageNum
,
pageSize
:
queryParams
.
pageSize
,
queryParams
:
{
activityStartDate
:
queryParams
.
activityDate
[
0
],
activityEndDate
:
queryParams
.
activityDate
[
1
],
planStatus
:
queryParams
.
planStatus
,
province
:
queryParams
.
province
,
city
:
queryParams
.
city
,
dealerId
:
queryParams
.
zoneId
,
orgQcId
:
queryParams
.
warzoneId
,
employeeId
:
queryParams
.
employeeId
,
storeNameLike
:
queryParams
.
storeName
}
}
})
...
...
@@ -58,3 +65,21 @@ export function deletePlanAPI(data) {
data
})
}
// 经销商列表
export
function
getDealerListAPI
(
queryParams
)
{
return
request
({
baseURL
:
VITE_APP_PROMOTION
,
url
:
'/user/dealer/query/list'
,
})
}
// web 页面创建单条活动计划
export
function
addPlanByWebAPI
(
data
)
{
return
request
({
baseURL
:
VITE_APP_PROMOTION
,
url
:
'/plan/v2/core/save'
,
method
:
'POST'
,
data
})
}
\ No newline at end of file
src/api/promotion/task.js
浏览文件 @
afb35335
...
...
@@ -10,7 +10,7 @@ export const getWarZoneListAPI = () => {
method
:
'POST'
,
data
:
{
"orgNameLike1"
:
"战区"
,
// "orgName1": "重客运营
部"
"orgName1"
:
"重客销售
部"
}
})
}
...
...
src/views/promotion/plan/index.vue
浏览文件 @
afb35335
...
...
@@ -5,6 +5,7 @@
<el-form
:model=
"queryParams"
inline
label-width=
"68px"
>
<el-row>
<el-form-item
label=
"选择日期"
prop=
"date"
>
<el-date-picker
v-model=
"queryParams.activityDate"
...
...
@@ -16,20 +17,116 @@
:shortcuts=
"pickerOptions"
@
change=
"getPlanList"
/>
</el-form-item>
<el-form-item
label=
"上传计划"
>
<el-upload
class=
"upload-demo"
action=
"#"
accept=
".xls,.xlsx"
:http-request=
"uploadFile"
:show-file-list=
"false"
>
<template
#
trigger
>
<el-button
type=
"primary"
>
选择 Excel
</el-button>
</
template
>
</el-upload>
<el-form-item
label=
"活动状态"
prop=
"planStatus"
>
<el-select
v-model=
"queryParams.planStatus"
placeholder=
"请选择活动状态"
filterable
clearable
@
change=
"getPlanList"
>
<el-option
v-for=
"item in taskStatusList"
:key=
"item.value"
:label=
"item.label"
:value=
"item.value"
/>
</el-select>
</el-form-item>
</el-row>
<!-- 省市 -->
<el-row>
<el-form-item
label=
"区域查询"
prop=
"region"
>
<el-radio-group
v-model=
"queryParams.region"
@
change=
"regionChange"
>
<el-radio-button
label=
"全国"
value=
"全国"
/>
<el-radio-button
label=
"省"
value=
"省"
/>
<el-radio-button
label=
"省-市"
value=
"省-市"
/>
</el-radio-group>
</el-form-item>
<el-form-item
label=
"省份"
prop=
"province"
v-show=
"queryParams.region !== '全国'"
>
<el-select
v-model=
"queryParams.provinceId"
placeholder=
"请选择省"
@
change=
"getProCity"
filterable
clearable
>
<el-option
v-for=
"item in provinceList"
:key=
"item.value"
:label=
"item.label"
:value=
"item.value"
/>
</el-select>
</el-form-item>
<el-form-item
label=
"城市"
prop=
"city"
v-show=
"queryParams.region === '省-市'"
>
<el-select
v-model=
"queryParams.cityId"
placeholder=
"请选择市"
@
change=
"getPlanList"
filterable
clearable
>
<el-option
v-for=
"item in cityList"
:key=
"item.value"
:label=
"item.label"
:value=
"item.value"
/>
</el-select>
</el-form-item>
</el-row>
<el-row>
<el-form-item
label=
"经销商"
prop=
"zone"
>
<el-select
v-model=
"queryParams.zoneId"
placeholder=
"请选择经销商"
@
change=
"getPlanList"
filterable
clearable
>
<el-option
v-for=
"item in zoneList"
:key=
"item.value"
:label=
"item.label"
:value=
"item.value"
/>
</el-select>
</el-form-item>
<el-form-item
label=
"战区查询"
prop=
"warzone"
>
<el-select
v-model=
"queryParams.warzoneId"
placeholder=
"请选择战区"
filterable
clearable
@
change=
"getPlanList"
>
<el-option
v-for=
"item in warZoneList"
:key=
"item.value"
:label=
"item.label"
:value=
"item.value"
/>
</el-select>
</el-form-item>
<el-form-item
label=
"归属人"
prop=
"manager"
>
<el-select
v-model=
"queryParams.employeeId"
placeholder=
"请选择归属人(搜索)"
filterable
clearable
:disabled=
"cityManagerPrivilege"
@
change=
"getPlanList"
>
<el-option
v-for=
"item in managerList"
:key=
"item.value"
:label=
"item.label"
:value=
"item.value"
/>
</el-select>
</el-form-item>
<el-form-item
label=
"终端名"
prop=
"store"
>
<el-input
v-model=
"queryParams.storeName"
clearable
placeholder=
"请输入门店名称"
@
input=
"getPlanList"
/>
</el-form-item>
</el-row>
</el-form>
<el-row
:gutter=
"10"
class=
"mb8"
>
class=
"mb8"
justify=
"space-between"
>
<el-col
:span=
"1.5"
>
<el-button
type=
"danger"
plain
...
...
@@ -37,6 +134,22 @@
:disabled=
"multiple"
@
click=
"handleDelete"
v-hasPermi=
"['system:user:remove']"
>
删除
</el-button>
<el-button
type=
"success"
plain
icon=
"Plus"
@
click=
"handleAdd"
v-hasPermi=
"['system:user:remove']"
>
新增
</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"
>
上传计划
</el-button>
</
template
>
</el-upload>
</el-col>
</el-row>
<!-- 表格列表 -->
...
...
@@ -58,8 +171,14 @@
:width=
"item.width"
:formatter=
"formatter"
:fixed=
"item.fixed"
/>
<el-table-column
label=
"操作"
>
<el-table-column
label=
"操作"
width=
"150"
>
<
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)"
...
...
@@ -108,24 +227,231 @@
</div>
</
template
>
</el-dialog>
<!-- 新增/修改计划 -->
<el-dialog
:title=
"(addOrEditPlanForm.id ? '修改' : '新增') + '计划'"
v-model=
"addOrEditPlanVisible"
width=
"60%"
>
<!-- 日期表单 -->
<el-form
:model=
"addOrEditPlanForm"
label-width=
"150px"
:rules=
"addOrEditPlanFormRules"
inline
>
<el-row>
<el-col
:span=
"10"
>
<!-- 门店编码 -->
<el-form-item
label=
"门店编码"
prop=
"storeCode"
>
<el-input
v-model=
"addOrEditPlanForm.storeCode"
placeholder=
"请输入门店编码"
/>
</el-form-item>
</el-col>
<el-col
:span=
"10"
>
<!-- 活动日期 -->
<el-form-item
label=
"活动日期"
prop=
"date"
>
<el-date-picker
v-model=
"addOrEditPlanForm.date"
:clearable=
"false"
start-placeholder=
"活动日期"
:disabled-date=
"disabledDateFn"
/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<!-- 活动模式 -->
<el-col
:span=
"10"
>
<el-form-item
label=
"活动模式"
prop=
"pattern"
>
<el-select
v-model=
"addOrEditPlanForm.pattern"
placeholder=
"请选择活动模式"
filterable
clearable
style=
"width: 95%"
>
<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=
"10"
v-if=
"!cityManagerPrivilege"
>
<!-- 归属人 -->
<el-form-item
label=
"归属人"
prop=
"employeeNo"
>
<el-select
v-model=
"addOrEditPlanForm.employeeNo"
placeholder=
"请选择归属人"
filterable
clearable
style=
"width: 95%"
>
<el-option
v-for=
"item in managerList"
:key=
"item.value"
:label=
"item.label"
:value=
"item.value"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col
:span=
"10"
>
<!-- 上班打卡时间 -->
<el-form-item
label=
"上班打卡时间"
prop=
"clockInTime"
>
<el-time-picker
v-model=
"addOrEditPlanForm.clockInTime"
placeholder=
"选择时间"
format=
"HH:mm:ss"
style=
"width: 95%"
/>
</el-form-item>
</el-col>
<el-col
:span=
"10"
>
<!-- 下班打卡时间 -->
<el-form-item
label=
"下班打卡时间"
prop=
"clockOutTime"
>
<el-time-picker
v-model=
"addOrEditPlanForm.clockOutTime"
placeholder=
"选择时间"
format=
"HH:mm:ss"
style=
"width: 95%"
:disabled=
"!addOrEditPlanForm.clockInTime"
:disabled-hours=
"disabledHours"
:disabled-minutes=
"disabledMinutes"
:disabled-seconds=
"disabledSeconds"
/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col
:span=
"10"
>
<!-- 工资 -->
<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=
"10"
>
<!-- 杂费 -->
<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"
>
取消
</el-button>
<el-button
type=
"primary"
@
click=
"handleAddOrEditPlan"
>
确定保存
</el-button>
</div>
</
template
>
</el-dialog>
</div>
</div>
</template>
<
script
setup
>
import
{
getPlanListAPI
,
uploadFileToOSSAPI
,
addPlanAPI
,
savePlanAPI
,
deletePlanAPI
,
addPlanByRoleAPI
}
from
'@/api'
import
{
getPlanListAPI
,
uploadFileToOSSAPI
,
addPlanAPI
,
savePlanAPI
,
deletePlanAPI
,
addPlanByRoleAPI
,
getProCityAPI
,
getDealerListAPI
,
getWarZoneListAPI
,
getChargeListAPI
,
addPlanByWebAPI
}
from
'@/api'
import
{
useDatePickerOptions
}
from
'@/hooks'
import
{
v4
as
uuidv4
}
from
'uuid'
;
import
store
from
'@/store'
import
{
parseTime
}
from
'@/utils'
import
{
ElMessage
}
from
'element-plus'
;
// 城市经理状态为 true
const
cityManagerPrivilege
=
computed
(()
=>
{
return
store
.
state
?.
value
?.
user
?.
userInfo
?.
privilegeId
==
1
})
const
{
recentPickerOptions
:
pickerOptions
,
thisYearDate
}
=
useDatePickerOptions
(
0
)
const
queryParams
=
reactive
({
pageNum
:
1
,
pageSize
:
10
,
activityDate
:
thisYearDate
activityDate
:
thisYearDate
,
region
:
'全国'
,
})
const
taskStatusList
=
ref
([
{
label
:
'执行'
,
value
:
'EXECUTION'
},
{
label
:
'未执行'
,
value
:
'NOT_EXECUTION'
}
])
// 查询参数-区域查询
const
provinceList
=
ref
([])
const
cityList
=
ref
([])
const
getProCity
=
async
()
=>
{
const
{
data
}
=
await
getProCityAPI
(
queryParams
)
if
(
queryParams
.
provinceId
)
{
queryParams
.
cityId
=
undefined
cityList
.
value
=
data
.
map
(
item
=>
({
label
:
item
.
name
,
value
:
item
.
num
}))
}
else
{
provinceList
.
value
=
data
.
map
(
item
=>
({
label
:
item
.
name
,
value
:
item
.
num
}))
}
getPlanList
()
}
getProCity
()
// 查询经销商列表
const
zoneList
=
ref
([])
const
getDealerList
=
async
()
=>
{
const
{
data
}
=
await
getDealerListAPI
()
zoneList
.
value
=
data
.
map
(
item
=>
{
return
{
label
:
item
.
dealerName
,
value
:
item
.
dealerId
}
})
}
getDealerList
()
// 查询战区列表
const
warZoneList
=
ref
([])
const
getWarZoneList
=
async
()
=>
{
const
{
data
}
=
await
getWarZoneListAPI
()
warZoneList
.
value
=
data
.
map
(
item
=>
{
return
{
label
:
item
.
orgName
,
value
:
item
.
qcId
}
})
}
getWarZoneList
()
// 查询负责人列表
const
managerList
=
ref
([])
const
getChargeList
=
async
()
=>
{
const
{
data
}
=
await
getChargeListAPI
()
managerList
.
value
=
data
.
map
(
item
=>
{
return
{
label
:
item
.
empName
,
value
:
item
.
empCode
,
}
})
}
getChargeList
()
// 区域查询切换
const
regionChange
=
(
val
)
=>
{
if
(
val
===
'全国'
)
{
queryParams
.
provinceId
=
undefined
queryParams
.
cityId
=
undefined
}
else
if
(
val
===
'省'
)
{
queryParams
.
cityId
=
undefined
}
getPlanList
()
}
// 等待被删除的数据
const
deleteList
=
ref
([])
...
...
@@ -238,18 +564,26 @@ const columns = ref([
// prop: 'city',
// width: 100
// },
{
label
:
'创建人'
,
prop
:
'createBy'
,
width
:
100
},
{
label
:
'最近修改人'
,
prop
:
'modifyBy'
,
width
:
100
},
{
label
:
'最后修改时间'
,
prop
:
'modifyTime'
,
width
:
250
},
{
label
:
'上传文件名称'
,
prop
:
''
,
width
:
150
}
])
const
getPlanList
=
async
()
=>
{
// 后台省市不要 id,自己查个名字给后台
queryParams
.
province
=
provinceList
.
value
.
find
(
item
=>
item
.
value
===
queryParams
.
provinceId
)?.
label
queryParams
.
city
=
cityList
.
value
.
find
(
item
=>
item
.
value
===
queryParams
.
cityId
)?.
label
const
res
=
await
getPlanListAPI
(
queryParams
)
tableList
.
value
=
res
.
data
.
records
total
.
value
=
res
.
data
.
totalRecord
...
...
@@ -289,7 +623,7 @@ const tableRowTimeOutClassName = ({ row }) => {
}
}
// 上传计划
// 上传计划
表格
const
uploadFile
=
async
(
file
)
=>
{
// 拼接当前月数为文件夹名
...
...
@@ -342,6 +676,143 @@ const confirmPlanBtn = async () => {
getPlanList
()
}
// 新增/编辑计划
const
addOrEditPlanVisible
=
ref
(
false
)
const
addOrEditPlanForm
=
reactive
({
})
// 新增/编辑计划-表单验证(所有都是必填项
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'
}
],
clockInTime
:
[
{
required
:
true
,
message
:
'请选择上班打卡时间'
,
trigger
:
'blur'
}
],
clockOutTime
:
[
{
required
:
true
,
message
:
'请选择下班打卡时间'
,
trigger
:
'blur'
}
],
salary
:
[
{
required
:
true
,
message
:
'请输入工资'
,
trigger
:
'blur'
}
],
incidentals
:
[
{
required
:
true
,
message
:
'请输入杂费'
,
trigger
:
'blur'
}
]
})
// 定义禁用日期的函数
const
disabledDateFn
=
(
time
)
=>
{
// 判断日期不在某个区间的就禁用
// 职能角色今日到次月最后一天
if
(
store
.
state
.
value
.
user
.
userInfo
.
privilegeId
===
1
)
{
const
now
=
new
Date
();
const
start
=
new
Date
(
now
.
getFullYear
(),
now
.
getMonth
(),
now
.
getDate
());
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
nextMonth
=
now
.
getMonth
()
+
1
;
const
start
=
new
Date
(
now
.
getFullYear
(),
nextMonth
,
1
);
const
end
=
new
Date
(
now
.
getFullYear
(),
nextMonth
+
1
,
0
);
return
time
.
getTime
()
<
start
.
getTime
()
||
time
.
getTime
()
>
end
.
getTime
();
}
}
const
handleAdd
=
()
=>
{
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
.
clockInTime
)
return
makeRange
(
0
,
date
.
getHours
()
-
1
);
}
const
disabledMinutes
=
(
h
,
m
)
=>
{
const
date
=
new
Date
(
addOrEditPlanForm
.
clockInTime
)
return
makeRange
(
0
,
date
.
getMinutes
()
-
1
);
}
const
disabledSeconds
=
(
h
,
m
,
s
)
=>
{
const
date
=
new
Date
(
addOrEditPlanForm
.
clockInTime
)
return
makeRange
(
0
,
date
.
getSeconds
()
-
1
);
}
// 编辑计划
const
editFn
=
(
row
)
=>
{
addOrEditPlanVisible
.
value
=
true
}
// 保存新增/编辑计划
const
handleAddOrEditPlan
=
async
()
=>
{
addOrEditPlanForm
.
operNo
=
store
.
state
.
value
.
user
.
userInfo
.
userName
addOrEditPlanForm
.
operName
=
store
.
state
.
value
.
user
.
userInfo
.
nickName
addOrEditPlanForm
.
operId
=
store
.
state
.
value
.
user
.
userInfo
.
userId
await
addPlanByWebAPI
(
addOrEditPlanForm
)
ElMessage
.
success
(
'保存成功'
)
addOrEditPlanVisible
.
value
=
false
}
// 删除计划
const
deletePlane
=
(
row
)
=>
{
deleteList
.
value
=
[
row
]
...
...
@@ -360,14 +831,14 @@ const handleDelete = async () => {
<
style
scoped
lang=
"scss"
>
.el-table
{
opacity
:
1
;
::v-deep
(
.error-row
)
{
--el-table-tr-bg-color
:
var
(
--
el-color-error-light-9
);
}
/* 灰色过期行颜色 */
::v-deep
(
.timeout-row
)
{
--el-table-tr-bg-color
:
#e2e2e2
9e
;
--el-table-tr-bg-color
:
rgb
(
215
,
215
,
215
)
;
}
}
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论