Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
W
wangxiaolu-sfa-ui
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
sfa
wangxiaolu-sfa-ui
Commits
6bf26d6d
提交
6bf26d6d
authored
12月 18, 2025
作者:
lidongxu
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'ap'
上级
dc61f15e
f6303ce6
全部展开
隐藏空白字符变更
内嵌
并排
正在显示
44 个修改的文件
包含
2009 行增加
和
12 行删除
+2009
-12
display_schedule.js
src/api/promotion/display_schedule.js
+29
-2
display_schedule_dashboard.js
src/api/promotion/display_schedule_dashboard.js
+8
-0
element-ui.scss
src/assets/styles/element-ui.scss
+7
-1
main.js
src/main.js
+1
-1
request.js
src/utils/request.js
+58
-6
upload.js
src/utils/upload.js
+1
-0
index.vue
src/views/mobile/pages/menu/index.vue
+3
-2
index.vue
...pages/storeExecution/dashboard/components/Table/index.vue
+287
-0
index.vue
src/views/mobile/pages/storeExecution/dashboard/index.vue
+112
-0
data.jsx
...views/mobile/pages/storeExecution/dashboard/tabs/data.jsx
+427
-0
display.vue
...ws/mobile/pages/storeExecution/dashboard/tabs/display.vue
+101
-0
schedule.vue
...s/mobile/pages/storeExecution/dashboard/tabs/schedule.vue
+96
-0
schedule_dis.vue
...bile/pages/storeExecution/dashboard/tabs/schedule_dis.vue
+94
-0
six_little_diamonds.vue
...ges/storeExecution/dashboard/tabs/six_little_diamonds.vue
+94
-0
snack.vue
...iews/mobile/pages/storeExecution/dashboard/tabs/snack.vue
+181
-0
three_two_seconds.vue
...pages/storeExecution/dashboard/tabs/three_two_seconds.vue
+97
-0
index.vue
...ges/storeExecution/report/components/SearchList/index.vue
+263
-0
index.vue
...le/pages/storeExecution/report/components/Table/index.vue
+0
-0
index.vue
src/views/mobile/pages/storeExecution/report/index.vue
+150
-0
data.jsx
src/views/mobile/pages/storeExecution/report/tabs/data.jsx
+0
-0
display.vue
...views/mobile/pages/storeExecution/report/tabs/display.vue
+0
-0
schedule.vue
...iews/mobile/pages/storeExecution/report/tabs/schedule.vue
+0
-0
schedule_dis.vue
.../mobile/pages/storeExecution/report/tabs/schedule_dis.vue
+0
-0
six_little_diamonds.vue
.../pages/storeExecution/report/tabs/six_little_diamonds.vue
+0
-0
snack.vue
src/views/mobile/pages/storeExecution/report/tabs/snack.vue
+0
-0
three_two_seconds.vue
...le/pages/storeExecution/report/tabs/three_two_seconds.vue
+0
-0
index.vue
...romotion/display_schedule/components/SearchList/index.vue
+0
-0
index.vue
...ews/promotion/display_schedule/components/Table/index.vue
+0
-0
data.jsx
src/views/promotion/display_schedule/tabs/data.jsx
+0
-0
display.vue
src/views/promotion/display_schedule/tabs/display.vue
+0
-0
schedule.vue
src/views/promotion/display_schedule/tabs/schedule.vue
+0
-0
schedule_dis.vue
src/views/promotion/display_schedule/tabs/schedule_dis.vue
+0
-0
six_little_diamonds.vue
...s/promotion/display_schedule/tabs/six_little_diamonds.vue
+0
-0
snack.vue
src/views/promotion/display_schedule/tabs/snack.vue
+0
-0
three_two_seconds.vue
...ews/promotion/display_schedule/tabs/three_two_seconds.vue
+0
-0
index.vue
...ion/display_schedule_dashboard/components/Table/index.vue
+0
-0
data.jsx
src/views/promotion/display_schedule_dashboard/tabs/data.jsx
+0
-0
display.vue
...ews/promotion/display_schedule_dashboard/tabs/display.vue
+0
-0
schedule.vue
...ws/promotion/display_schedule_dashboard/tabs/schedule.vue
+0
-0
schedule_dis.vue
...romotion/display_schedule_dashboard/tabs/schedule_dis.vue
+0
-0
six_little_diamonds.vue
...n/display_schedule_dashboard/tabs/six_little_diamonds.vue
+0
-0
snack.vue
...views/promotion/display_schedule_dashboard/tabs/snack.vue
+0
-0
three_two_seconds.vue
...ion/display_schedule_dashboard/tabs/three_two_seconds.vue
+0
-0
effectivePlan.vue
src/views/promotion/plan/effectivePlan.vue
+0
-0
没有找到文件。
src/api/promotion/display_schedule.js
浏览文件 @
6bf26d6d
...
...
@@ -157,4 +157,32 @@ export function submitSixLittleDiamondsPlan(data) {
}
}
});
}
\ No newline at end of file
}
// 下载表格
export
function
downloadDisplayScheduleTable
(
params
)
{
return
request
({
url
:
'/operation/sales/export/download'
,
params
,
responseType
:
'blob'
})
}
// 上传表格
export
function
uploadDisplayScheduleTable
(
data
)
{
return
request
({
url
:
'/operation/sales/import/upload'
,
method
:
'POST'
,
data
})
}
// 确定上传表格数据保存
export
function
confirmUploadDisplayScheduleTable
(
data
)
{
return
request
({
url
:
'/operation/sales/import/update'
,
method
:
'POST'
,
data
})
}
src/api/promotion/display_schedule_dashboard.js
浏览文件 @
6bf26d6d
...
...
@@ -12,4 +12,11 @@ export const getDisplayScheduleDashboardListArea = (params) => {
url
:
'/operation/sales/ap_report/query/store_cm'
,
params
})
}
// 查询,店内执行上报-看板(经销商)
export
const
getDisplayScheduleDashboardListStore
=
(
params
)
=>
{
return
request
({
url
:
'/operation/sales/ap_report/query/dist_cm'
,
params
})
}
\ No newline at end of file
src/assets/styles/element-ui.scss
浏览文件 @
6bf26d6d
...
...
@@ -48,7 +48,7 @@
// 重写 el-table 的 loading-mask 加载进度蒙层
.el-loading-mask
{
z-index
:
1
!
important
;
z-index
:
1
0000
!
important
;
}
// to fixed https://github.com/ElemeFE/element/issues/2461
...
...
@@ -212,4 +212,9 @@ html.dark {
.popup-result
.title
{
background
:
var
(
--
cron-border
);
}
}
// messageBox 样式
.is-message-box
{
z-index
:
10000
!
important
;
}
\ No newline at end of file
src/main.js
浏览文件 @
6bf26d6d
...
...
@@ -69,7 +69,7 @@ import VConsole from 'vconsole'
// 创建vConsole实例
// 生产环境不加载
if
(
import
.
meta
.
env
.
VITE_APP_ENV
===
'staging
'
)
{
if
(
import
.
meta
.
env
.
VITE_APP_ENV
!==
'production
'
)
{
new
VConsole
()
}
...
...
src/utils/request.js
浏览文件 @
6bf26d6d
...
...
@@ -16,6 +16,58 @@ export let isRelogin = { show: false };
// 促销系统后台 baseURL
export
const
promotionBaseURL
=
import
.
meta
.
env
.
VITE_APP_PROMOTION
// 错误消息队列和状态管理
let
errorMessageQueue
=
[];
let
isShowingError
=
false
;
let
lastErrorTime
=
0
;
const
ERROR_DEBOUNCE_TIME
=
1000
;
// 1秒内的错误视为同一批
// 显示错误消息(单例模式)
function
showErrorMessage
(
message
,
type
=
'error'
)
{
const
now
=
Date
.
now
();
// 如果正在显示错误消息,或者距离上次错误时间很短,将消息加入队列
if
(
isShowingError
||
(
now
-
lastErrorTime
<
ERROR_DEBOUNCE_TIME
))
{
// 检查队列中是否已有相同消息,避免重复
const
existingIndex
=
errorMessageQueue
.
findIndex
(
item
=>
item
.
message
===
message
);
if
(
existingIndex
===
-
1
)
{
errorMessageQueue
.
push
({
message
,
type
});
}
return
;
}
// 标记为正在显示
isShowingError
=
true
;
lastErrorTime
=
now
;
// 显示当前错误消息
ElMessage
({
message
:
message
,
type
:
type
,
duration
:
3000
,
// 适当延长显示时间
onClose
:
()
=>
{
isShowingError
=
false
;
// 检查队列中是否有待显示的消息
if
(
errorMessageQueue
.
length
>
0
)
{
// 延迟一段时间再显示下一条,避免消息切换太快
setTimeout
(()
=>
{
const
nextError
=
errorMessageQueue
.
shift
();
if
(
nextError
)
{
showErrorMessage
(
nextError
.
message
,
nextError
.
type
);
}
},
500
);
}
}
});
}
// 清空错误消息队列(可选,在某些场景下可能需要)
export
function
clearErrorMessageQueue
()
{
errorMessageQueue
=
[];
isShowingError
=
false
;
}
axios
.
defaults
.
headers
[
'Content-Type'
]
=
'application/json;charset=utf-8'
// 创建axios实例
const
service
=
axios
.
create
({
...
...
@@ -114,7 +166,6 @@ service.interceptors.response.use(async res => {
isRelogin
.
show
=
false
;
});
return
Promise
.
reject
(
'无效的会话,或者会话已过期,请重新登录。'
)
}
else
if
(
code
===
403
)
{
// 如果刷新 refreshToken 接口也报错了,证明需要重新登录
// ElMessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', { confirmButtonText: '重新登录', cancelButtonText: '取消', type: 'warning' }).then(() => {
...
...
@@ -126,16 +177,17 @@ service.interceptors.response.use(async res => {
// isRelogin.show = false;
// });
// return Promise.reject('无效的会话,或者会话已过期,请重新登录。')
ElMessage
({
message
:
msg
,
type
:
'error'
})
showErrorMessage
(
msg
,
'error'
)
return
Promise
.
reject
(
new
Error
(
msg
))
}
else
if
(
code
===
500
)
{
ElMessage
({
message
:
msg
,
type
:
'error'
}
)
showErrorMessage
(
msg
,
'error'
)
return
Promise
.
reject
(
new
Error
(
msg
))
}
else
if
(
code
===
601
)
{
ElMessage
({
message
:
msg
,
type
:
'warning'
}
)
showErrorMessage
(
msg
,
'warning'
)
return
Promise
.
reject
(
new
Error
(
msg
))
}
else
if
(
code
!==
200
)
{
ElNotification
.
error
({
title
:
msg
}
)
showErrorMessage
(
msg
,
'error'
)
return
Promise
.
reject
(
'error'
)
}
else
{
return
Promise
.
resolve
(
res
.
data
)
...
...
@@ -150,7 +202,7 @@ service.interceptors.response.use(async res => {
}
else
if
(
message
.
includes
(
"Request failed with status code"
))
{
message
=
"系统接口"
+
message
.
substr
(
message
.
length
-
3
)
+
"异常"
;
}
ElMessage
({
message
:
message
,
type
:
'error'
,
duration
:
5
*
1000
}
)
showErrorMessage
(
message
,
'error'
)
return
Promise
.
reject
(
error
)
}
)
...
...
src/utils/upload.js
浏览文件 @
6bf26d6d
...
...
@@ -19,6 +19,7 @@ export const chooseFile = ({ accept, id = 'fileInput' }) => {
// 关闭窗口没选择文件
window
.
addEventListener
(
'cancel'
,
()
=>
{
document
.
body
.
removeChild
(
fileInput
)
reject
(
'请选择文件'
)
})
document
.
body
.
appendChild
(
fileInput
)
fileInput
.
click
()
...
...
src/views/mobile/pages/menu/index.vue
浏览文件 @
6bf26d6d
...
...
@@ -92,7 +92,8 @@ const handleIconClick = (icon) => {
.mobile-container
{
background-color
:
#f3f3f3
;
min-height
:
100vh
;
font-size
:
14px
;
font-size
:
13px
;
// font-size: 12px;
padding
:
20px
;
p
{
...
...
@@ -125,7 +126,7 @@ const handleIconClick = (icon) => {
display
:
grid
;
grid-template-columns
:
repeat
(
4
,
1fr
);
/* 创建4列等宽布局 */
gap
:
10
px
;
gap
:
2
px
;
/* 列之间的间距 */
justify-content
:
space-between
;
/* 两边对齐 */
...
...
src/views/mobile/pages/storeExecution/dashboard/components/Table/index.vue
0 → 100644
浏览文件 @
6bf26d6d
<
template
>
<div
class=
"flex-container"
>
<!-- 操作类型 -->
<el-row>
<el-form-item>
<el-radio-group
v-model=
"operation"
@
change=
"handleChange"
>
<el-radio-button
label=
"大区战区-分析"
value=
"大区战区-分析"
v-hasPermi=
"['promotion:dashboard:list-show']"
/>
<el-radio-button
label=
"城市经理-分析"
value=
"城市经理-分析"
/>
</el-radio-group>
</el-form-item>
</el-row>
<el-table
:data=
"tableData"
border
ref=
"tableRef"
v-loading=
"isLoading"
show-overflow-tooltip
>
<template
v-for=
"col in chooseColumns"
:key=
"col.prop"
>
<!-- 有子列的情况 -->
<el-table-column
v-if=
"col.childColumns && col.childColumns.length > 0"
:label=
"col.label"
align=
"center"
:width=
"col.width"
>
<el-table-column
v-for=
"childCol in col.childColumns"
:key=
"childCol.prop"
:label=
"childCol.label"
:prop=
"childCol.prop"
align=
"center"
:width=
"childCol.width"
>
</el-table-column>
</el-table-column>
<!-- 没有子列的独立列情况 -->
<el-table-column
v-else
:label=
"col.label"
:prop=
"col.prop"
align=
"center"
:width=
"col.width"
>
</el-table-column>
</
template
>
</el-table>
</div>
</template>
<
script
setup
>
import
userStore
from
'@/store/modules/user'
const
props
=
defineProps
({
tableData
:
{
// 数据源
type
:
Array
,
default
:
()
=>
[]
},
baseColumns
:
{
// 表格列
type
:
Array
,
default
:
()
=>
[]
},
total
:
{
// 总条数
type
:
Number
,
default
:
0
},
isLoading
:
{
// 表格加载状态
type
:
Boolean
,
default
:
false
},
formatter
:
{
// 格式化函数
type
:
Function
,
default
:
(
row
,
col
,
cellValue
)
=>
cellValue
}
})
const
emit
=
defineEmits
([
'getTableList'
])
/*************** 工具栏 ***************/
const
operation
=
ref
(
''
);
// 切换平铺/填报模式
const
tableRef
=
ref
(
null
)
const
chooseColumns
=
ref
([])
// 使用的列
// 检查用户是否有特定权限的辅助函数
const
hasPermission
=
(
permission
)
=>
{
return
userStore
().
permissions
.
includes
(
permission
)
}
// 根据权限动态设置默认选中的值
onMounted
(()
=>
{
// 优先检查是否有'promotion:dashboard:list-show'权限,如果有则选中'大区战区-分析'
if
(
hasPermission
(
'promotion:dashboard:list-show'
))
{
operation
.
value
=
'大区战区-分析'
}
else
{
// 否则默认选中'城市经理-分析'
operation
.
value
=
'城市经理-分析'
}
// 初始化列选择
initColumns
()
})
// 初始化列选择的函数
const
initColumns
=
()
=>
{
if
(
operation
.
value
===
'大区战区-分析'
)
{
chooseColumns
.
value
=
props
.
baseColumns
.
filter
(
item
=>
item
.
prop
!==
'cityManager'
)
}
else
{
chooseColumns
.
value
=
props
.
baseColumns
}
}
watch
(
operation
,
(
newVal
)
=>
{
// 如果是大区战区-分析,则隐藏城市经理列
if
(
newVal
===
'大区战区-分析'
)
{
chooseColumns
.
value
=
props
.
baseColumns
.
filter
(
item
=>
item
.
prop
!==
'cityManager'
)
}
else
{
chooseColumns
.
value
=
props
.
baseColumns
}
},
{
immediate
:
true
})
// 切换操作类型时触发的函数
const
handleChange
=
(
newVal
)
=>
{
emit
(
'getTableList'
,
newVal
)
}
</
script
>
<
style
scoped
lang=
"scss"
>
/* 根容器设置为flex布局,占据整个可用空间 */
.flex-container
{
flex
:
1
;
display
:
flex
;
flex-direction
:
column
;
overflow
:
hidden
;
/* 表格样式 */
.table-container
{
flex
:
1
;
/* 这是关键,让表格容器自动占据剩余空间 */
display
:
flex
;
flex-direction
:
column
;
min-height
:
0
;
/* 解决flex子项内容溢出问题 */
.auto-fit-header-table
{
flex
:
1
;
/* 列样式 */
.column-style
{
/* 列头样式 */
.formula-column
{
display
:
flex
;
justify-content
:
center
;
align-items
:
center
;
.column
{
display
:
flex
;
justify-content
:
center
;
align-items
:
center
;
flex-direction
:
column
;
p
{
margin
:
0
;
font-size
:
12px
;
color
:
#606266
;
}
}
.el-icon
{
margin-left
:
2px
;
}
}
/* 单元格样式 */
/* 展示模式单元格(仅展示模式生效) */
.show-cell-style
{
overflow
:
hidden
;
text-overflow
:
ellipsis
;
white-space
:
nowrap
;
}
/* 自定义单元格样式(仅填充模式生效) */
.cell-style
{
>
div
{
display
:
flex
;
flex-direction
:
column
;
align-items
:
center
;
>
span
{
text-align
:
left
;
text-indent
:
5px
;
display
:
inline-block
;
width
:
80%
;
background-color
:
#e1e2e6
;
border-bottom
:
1px
solid
#ebeef5
;
}
}
/* 表格内下拉框 */
.el-select
{
width
:
100%
!
important
;
padding
:
10px
;
/* 非 disabled 状态下的背景颜色 */
&.
no-disabled
:
:
v-deep
(
.
el-select__wrapper
)
{
border
:
4px
solid
var
(
--
el-background-editor-cell
)
!
important
;
}
}
.el-input
{
height
:
32px
!
important
;
/* box-sizing: content-box; */
padding
:
0
10px
;
width
:
100%
;
/* 非 disabled 状态下的背景颜色 */
&.
no-disabled
:
:
v-deep
(
.
el-input__wrapper
)
{
border
:
4px
solid
var
(
--
el-background-editor-cell
)
!
important
;
}
}
.date-picker
{
width
:
100%
;
padding
:
10px
;
/* 非 disabled 状态下的背景颜色 */
&.
no-disabled
:
:
v-deep
(
.
el-input__wrapper
)
{
border
:
4px
solid
var
(
--
el-background-editor-cell
)
!
important
;
}
::v-deep
(
.el-input
)
{
width
:
100%
;
padding
:
0
;
}
}
}
/* 普通文字单元格(仅填充模式生效) */
.fill-span-wrap
{
/* 超出省略号 */
overflow
:
hidden
;
text-overflow
:
ellipsis
;
white-space
:
nowrap
;
padding
:
0
10px
;
}
}
/* 填报模式-单元格 */
&
.cell-no-padding
{
/* 无上下内边距 */
::v-deep
(
.el-table__row
)
{
.el-table__cell
{
padding-top
:
0
;
padding-bottom
:
0
;
.cell
{
padding
:
0
!
important
;
}
}
}
}
}
/* 分页器 */
.pagination-container
{
margin
:
10px
;
}
}
}
/* 加深表头背景颜色 */
::v-deep
(
.el-table__header-wrapper
)
{
.el-table__header
{
th
{
background-color
:
#dcdfe6
!
important
;
color
:
#303133
!
important
;
font-weight
:
bold
;
}
}
}
</
style
>
src/views/mobile/pages/storeExecution/dashboard/index.vue
0 → 100644
浏览文件 @
6bf26d6d
<
template
>
<div
class=
"app-container"
>
<div
class=
"container"
>
<van-nav-bar
fixed
left-arrow
@
click-left=
"router.back()"
title=
"店内执行上报看板"
/>
<el-tabs
v-model=
"activeName"
class=
"demo-tabs"
@
tab-click=
"handleClickTabs"
>
<el-tab-pane
label=
"常规陈列"
name=
"常规陈列"
>
<Display
/>
</el-tab-pane>
<el-tab-pane
label=
"档期计划"
name=
"档期计划"
>
<Schedule
/>
</el-tab-pane>
<el-tab-pane
label=
"档期陈列"
name=
"档期陈列"
>
<ScheduleDis
/>
</el-tab-pane>
<el-tab-pane
label=
"零食陈列"
name=
"零食陈列"
>
<Snack
/>
</el-tab-pane>
<el-tab-pane
label=
"三米两秒"
name=
"三米两秒"
>
<ThreeTwoSeconds
/>
</el-tab-pane>
<el-tab-pane
label=
"六小金刚"
name=
"六小金刚"
>
<SixLittleDiamonds
/>
</el-tab-pane>
</el-tabs>
</div>
</div>
</
template
>
<
script
setup
>
import
Display
from
'./tabs/display.vue'
import
Schedule
from
'./tabs/schedule.vue'
import
ScheduleDis
from
'./tabs/schedule_dis.vue'
import
Snack
from
'./tabs/snack.vue'
import
ThreeTwoSeconds
from
'./tabs/three_two_seconds.vue'
import
SixLittleDiamonds
from
'./tabs/six_little_diamonds.vue'
const
router
=
useRouter
()
const
activeName
=
ref
(
'常规陈列'
);
const
handleClickTabs
=
(
tab
)
=>
{
activeName
.
value
=
tab
.
name
;
}
</
script
>
<
style
scoped
lang=
"scss"
>
.app-container
{
padding
:
10px
;
padding-top
:
46px
;
.container
{
padding
:
10px
;
.el-tabs
{
height
:
100%
;
display
:
flex
;
flex-direction
:
column-reverse
;
::v-deep
(
.el-tabs__header
)
{
// 确保底部边框线完整显示
border-bottom
:
1px
solid
var
(
--
el-border-color-light
);
width
:
100%
;
}
::v-deep
(
.el-tabs__nav-wrap
)
{
overflow-x
:
auto
;
overflow-y
:
hidden
;
-webkit-overflow-scrolling
:
touch
;
// iOS平滑滚动
scrollbar-width
:
none
;
// Firefox隐藏滚动条
&
:
:
after
{
// 隐藏el-tabs默认的底部伪元素边框
display
:
none
;
}
&
:
:-
webkit-scrollbar
{
display
:
none
;
// Chrome/Safari隐藏滚动条
}
}
::v-deep
(
.el-tabs__nav-scroll
)
{
overflow
:
visible
;
width
:
max-content
;
}
::v-deep
(
.el-tabs__content
)
{
display
:
flex
;
flex-direction
:
column
;
overflow-y
:
scroll
;
// height: 100%;
.el-tab-pane
{
// height: 100%;
display
:
flex
;
flex-direction
:
column
;
}
}
}
}
}
</
style
>
\ No newline at end of file
src/views/mobile/pages/storeExecution/dashboard/tabs/data.jsx
0 → 100644
浏览文件 @
6bf26d6d
// 每个表格里的数据列信息集合
// 常规陈列
export
const
getDisplayConfig
=
()
=>
{
return
[
// {
// label: "计划月份",
// prop: "salesMonth",
// width: 100,
// childCol: []
// },
{
label
:
"大区"
,
prop
:
"regionName"
,
childCol
:
[]
},
{
label
:
"战区"
,
prop
:
"districtName"
,
childCol
:
[],
width
:
110
},
{
label
:
"城市经理"
,
prop
:
"cityManager"
,
childCol
:
[]
},
{
label
:
'主货架'
,
prop
:
"mainShelf"
,
childColumns
:
[
{
label
:
'计划'
,
prop
:
"planMsStoreCnt"
,
},
{
label
:
'执行'
,
prop
:
"execMsStoreCnt"
,
},
{
label
:
'执行率'
,
prop
:
"msExecRate"
,
width
:
90
}
]
},
{
label
:
'端架'
,
prop
:
"endShelf"
,
childColumns
:
[
{
label
:
'计划'
,
prop
:
"planRegEndcapStoreCnt"
,
},
{
label
:
'执行'
,
prop
:
"execRegEndcapStoreCnt"
,
},
{
label
:
'执行率'
,
prop
:
"endcapExecRate"
,
width
:
90
}
]
},
{
label
:
'地堆'
,
prop
:
"endcapShelf"
,
childColumns
:
[
{
label
:
'计划'
,
prop
:
"planRegGsStoreCnt"
,
},
{
label
:
'执行'
,
prop
:
"execRegGsStoreCnt"
,
},
{
label
:
'执行率'
,
prop
:
"gsExecRate"
,
width
:
90
}
]
},
{
label
:
'多点陈列'
,
prop
:
"multiShelf"
,
childColumns
:
[
{
label
:
'计划'
,
prop
:
"planMpDispStoreCnt"
,
},
{
label
:
'执行'
,
prop
:
"execMpDispStoreCnt"
,
},
{
label
:
'执行率'
,
prop
:
"mpDispExecRate"
,
width
:
90
}
]
},
{
label
:
'挂条陈列'
,
prop
:
"hangShelf"
,
childColumns
:
[
{
label
:
'计划'
,
prop
:
"planHsStoreCnt"
,
},
{
label
:
'执行'
,
prop
:
"execHsStoreCnt"
,
},
{
label
:
'执行率'
,
prop
:
"HsExecRate"
,
width
:
90
}
]
}
]
}
// 档期计划
export
const
getSchedulePlanConfig
=
(
submitChange
)
=>
{
return
[
// {
// label: "计划月份",
// prop: "salesMonth",
// width: 100
// },
{
label
:
"大区"
,
prop
:
"regionName"
,
width
:
100
},
{
label
:
"战区"
,
prop
:
"districtName"
,
width
:
100
},
{
label
:
"城市经理"
,
prop
:
"cityManager"
,
width
:
100
},
{
label
:
'大区反馈'
,
prop
:
"regionFeedback"
,
childColumns
:
[
{
label
:
'计划'
,
prop
:
"planPromoPeriStoreCnt"
,
},
{
label
:
'执行'
,
prop
:
"launchPromoPeriStoreCnt"
,
},
{
label
:
'执行率'
,
prop
:
"launchRatePromoPeriExec"
,
width
:
90
}
]
},
{
label
:
'规格'
,
prop
:
"spec"
,
childColumns
:
[
{
label
:
'执行'
,
prop
:
"execPsStoreCnt"
,
},
{
label
:
'执行率'
,
prop
:
"psExecRatePromoPeriExec"
,
width
:
90
}
]
},
{
label
:
'口味'
,
prop
:
"flavor"
,
childColumns
:
[
{
label
:
'执行'
,
prop
:
"execPfStoreCnt"
,
},
{
label
:
'执行率'
,
prop
:
"pfExecRatePromoPeriExec"
,
width
:
90
}
]
},
{
label
:
'价格'
,
prop
:
"price"
,
childColumns
:
[
{
label
:
'执行'
,
prop
:
"execPpStoreCnt"
,
},
{
label
:
'执行率'
,
prop
:
"ppExecRatePromoPeriExec"
,
width
:
90
}
]
},
{
label
:
'海报'
,
prop
:
"poster"
,
childColumns
:
[
{
label
:
'计划'
,
prop
:
"planPosterStoreCnt"
,
},
{
label
:
'执行'
,
prop
:
"execPosterStoreCnt"
,
},
{
label
:
'执行率'
,
prop
:
"posterExecRate"
,
width
:
90
}
]
},
]
}
// 档期陈列
export
const
getScheduleDisConfig
=
(
submitChange
)
=>
{
return
[
// {
// label: "计划月份",
// prop: "salesMonth",
// width: 100
// },
{
label
:
"大区"
,
prop
:
"regionName"
,
width
:
100
},
{
label
:
"战区"
,
prop
:
"districtName"
,
width
:
100
},
{
label
:
"城市经理"
,
prop
:
"cityManager"
,
width
:
100
},
{
label
:
'端架'
,
prop
:
"endShelf"
,
childColumns
:
[
{
label
:
'计划'
,
prop
:
"planEndcapStoreCnt"
,
},
{
label
:
'执行'
,
prop
:
"execEndcapStoreCnt"
,
},
{
label
:
'执行率'
,
prop
:
"endcapExecRatePromoPeriDisp"
,
}
]
},
{
label
:
'地堆'
,
prop
:
"endcapShelf"
,
childColumns
:
[
{
label
:
'计划'
,
prop
:
"planGsStoreCnt"
,
},
{
label
:
'执行'
,
prop
:
"execGsStoreCnt"
,
},
{
label
:
'执行率'
,
prop
:
"gsExecRatePromoPeriDisp"
,
}
]
},
{
label
:
'其他陈列'
,
prop
:
"otherShelf"
,
childColumns
:
[
{
label
:
'计划'
,
prop
:
"planOtherDispStoreCnt"
,
},
{
label
:
'执行'
,
prop
:
"execOtherDispStoreCnt"
,
},
{
label
:
'执行率'
,
prop
:
"otherDispExecRatePromoPeriDisp"
,
}
]
},
]
}
// 零食陈列
export
const
getSnackCofing
=
(
submitChange
)
=>
{
return
[
// {
// label: "计划月份",
// prop: "salesMonth",
// width: 100
// },
{
label
:
"大区"
,
prop
:
"regionName"
,
width
:
100
},
{
label
:
"战区"
,
prop
:
"districtName"
,
width
:
100
},
{
label
:
"城市经理"
,
prop
:
"cityManager"
,
width
:
100
},
{
label
:
'计划'
,
prop
:
"planSnackStoreCnt"
,
},
{
label
:
'执行'
,
prop
:
"execSnackStoreCnt"
,
},
{
label
:
'执行率'
,
prop
:
"snackExecRate"
,
}
]
}
// 三米两秒
export
const
getThreeTwoSecondsConfig
=
(
submitChange
)
=>
{
return
[
// {
// label: "计划月份",
// prop: "salesMonth",
// width: 100
// },
{
label
:
"大区"
,
prop
:
"regionName"
,
width
:
100
},
{
label
:
"战区"
,
prop
:
"districtName"
,
width
:
100
},
{
label
:
"城市经理"
,
prop
:
"cityManager"
,
width
:
100
},
{
label
:
'计划'
,
prop
:
"planSLStoreCnt"
,
},
{
label
:
'执行'
,
prop
:
"execSLStoreCnt"
,
},
{
label
:
'执行率'
,
prop
:
"SLExecRate"
,
}
]
}
// 六小金刚
export
const
getSixLittleDiamondsConfig
=
(
submitChange
)
=>
{
return
[
// {
// label: "计划月份",
// prop: "salesMonth",
// width: 100
// },
{
label
:
"大区"
,
prop
:
"regionName"
,
width
:
100
},
{
label
:
"战区"
,
prop
:
"districtName"
,
width
:
100
},
{
label
:
"城市经理"
,
prop
:
"cityManager"
,
width
:
100
},
{
label
:
'计划'
,
prop
:
"planSixJdStoreCnt"
,
},
{
label
:
'执行'
,
prop
:
"execSixJdStoreCnt"
,
},
{
label
:
'执行率'
,
prop
:
"sixJdExecRate"
,
}
]
}
src/views/mobile/pages/storeExecution/dashboard/tabs/display.vue
0 → 100644
浏览文件 @
6bf26d6d
<
template
>
<!-- 常规陈列 -->
<el-form
:inline=
"true"
:model=
"queryParams"
class=
"demo-form-inline"
>
<el-form-item
label=
"计划月份"
>
<el-date-picker
v-model=
"queryParams.salesMonth"
type=
"month"
placeholder=
"选择计划月份"
@
change=
"getTableList"
clearable
/>
</el-form-item>
</el-form>
<CustomTable
:tableData=
"tableData"
:baseColumns=
"baseColumns"
:isLoading=
"isLoading"
@
getTableList=
"getTableList"
@
updateShowSearch=
"v => showSearch.value = v"
/>
</
template
>
<
script
setup
lang=
"jsx"
>
import
CustomTable
from
'../components/Table'
import
{
getDisplayScheduleDashboardList
,
getDisplayScheduleDashboardListArea
}
from
'@/api'
import
{
getDisplayConfig
}
from
'./data.jsx'
import
{
parseTime
}
from
'@/utils'
/*************** 表格操作相关 ***************/
// 提交变更
const
tableColumns
=
getDisplayConfig
()
// 全部列
const
baseColumns
=
ref
(
tableColumns
);
// 表格数据
const
queryParams
=
reactive
({
salesMonth
:
new
Date
(),
})
const
tableData
=
ref
([])
const
isLoading
=
ref
(
true
)
const
total
=
ref
(
0
)
// 筛选列表数据
const
getTableList
=
async
(
operation
)
=>
{
isLoading
.
value
=
true
const
res
=
await
(
operation
===
'大区战区-分析'
?
getDisplayScheduleDashboardList
:
getDisplayScheduleDashboardListArea
)({
...
queryParams
,
salesMonth
:
parseTime
(
queryParams
.
salesMonth
,
'{y}-{m}'
)
})
if
(
operation
===
'大区战区-分析'
)
{
// 合并战区大区结构为扁平化
const
{
zq
,
dq
}
=
res
.
data
tableData
.
value
=
[...
zq
,
...
dq
]
}
else
{
// 合并城市经理结构为扁平化
tableData
.
value
=
res
.
data
}
isLoading
.
value
=
false
}
const
{
proxy
}
=
getCurrentInstance
()
const
isDaQuZQ
=
proxy
.
checkPermi
([
'promotion:dashboard:list-show'
])
getTableList
(
isDaQuZQ
?
'大区战区-分析'
:
'城市经理-分析'
)
</
script
>
<
style
lang=
"scss"
>
// 动态列内容的 render 内样式
// 操作提示列
.operation_tip_cell
{
display
:
flex
;
flex-direction
:
column
;
align-items
:
flex-start
;
p
{
width
:
100%
;
margin
:
0
;
}
p
:first-child
{
background-color
:
#e1e2e6
;
border-bottom
:
1px
solid
#ebeef5
;
}
p
:last-child
{
padding
:
15px
0
;
}
}
// 只在填报模式出现的门店名称+门店编码+经销山名称(合并到一起)
.store-name-render-cell
{
display
:
flex
;
flex-direction
:
column
;
align-items
:
flex-start
;
p
{
width
:
100%
;
margin
:
0
;
}
}
</
style
>
\ No newline at end of file
src/views/mobile/pages/storeExecution/dashboard/tabs/schedule.vue
0 → 100644
浏览文件 @
6bf26d6d
<
template
>
<!-- 档期计划 -->
<!-- 隐藏门店搜索 -->
<el-form
:inline=
"true"
:model=
"queryParams"
class=
"demo-form-inline"
>
<el-form-item
label=
"计划月份"
>
<el-date-picker
v-model=
"queryParams.salesMonth"
type=
"month"
placeholder=
"选择计划月份"
@
change=
"getTableList"
clearable
/>
</el-form-item>
</el-form>
<CustomTable
:tableData=
"tableData"
:baseColumns=
"baseColumns"
:isLoading=
"isLoading"
@
getTableList=
"getTableList"
@
updateShowSearch=
"v => showSearch.value = v"
/>
</
template
>
<
script
setup
lang=
"jsx"
>
import
CustomTable
from
'../components/Table'
import
{
getDisplayScheduleDashboardList
,
getDisplayScheduleDashboardListArea
}
from
'@/api'
import
{
parseTime
}
from
'@/utils'
import
{
getSchedulePlanConfig
}
from
'./data.jsx'
const
{
proxy
}
=
getCurrentInstance
()
/*************** 操作类型 ***************/
// 提交变更
const
submitChange
=
async
(
row
,
col
)
=>
{
// 需要特殊处理的
// 实际主货架-形式,为空时,置空实际主货架-数量
if
(
col
.
prop
===
'actualMainShelfType'
&&
!
row
.
actualMainShelfType
)
{
row
.
actualMainShelfQty
=
0
}
let
requestObj
=
{}
if
(
col
.
requestKey
)
{
// 关联的公式计算列,需要特殊处理
for
(
const
str
of
col
.
requestKey
)
{
const
obj
=
getSchedulePlanConfig
().
flatMap
(
item
=>
{
if
(
item
.
children
)
{
return
item
.
children
.
filter
(
child
=>
!
child
.
onlyFill
);
}
return
[];
}).
find
(
item
=>
item
.
prop
==
str
)
if
(
obj
&&
obj
.
type
===
'formula'
)
{
obj
.
func
(
row
)
}
}
requestObj
=
col
.
requestKey
.
reduce
((
acc
,
key
)
=>
({
...
acc
,
[
key
]:
row
[
key
]
}),
{})
}
await
submitDisplaySchedulePlan
({
id
:
row
.
sapId
,
[
col
.
prop
]:
row
[
col
.
prop
],
// 当前修改列的值
...
requestObj
,
actualPromotionFlavor
:
Array
.
isArray
(
row
.
actualPromotionFlavor
)
?
row
.
actualPromotionFlavor
.
join
(
','
)
:
'-'
,
// 档期执行-促销口味,为数组时,转成字符串
actualPromotionStartDate
:
row
.
actualPromotionStartDate
?
parseTime
(
row
.
actualPromotionStartDate
,
'{y}-{m}-{d}'
)
:
''
,
// 档期执行-促销开始日期,为字符串时,转成日期格式
})
}
// 基础列配置
const
baseColumns
=
ref
(
getSchedulePlanConfig
(
submitChange
));
// 表格数据
const
queryParams
=
reactive
({
salesMonth
:
new
Date
(),
})
const
tableData
=
ref
([])
const
isLoading
=
ref
(
true
)
const
total
=
ref
(
0
)
// 筛选列表数据
const
getTableList
=
async
(
operation
)
=>
{
isLoading
.
value
=
true
const
res
=
await
(
operation
===
'大区战区-分析'
?
getDisplayScheduleDashboardList
:
getDisplayScheduleDashboardListArea
)({
...
queryParams
,
salesMonth
:
parseTime
(
queryParams
.
salesMonth
,
'{y}-{m}'
)
})
if
(
operation
===
'大区战区-分析'
)
{
// 合并战区大区结构为扁平化
const
{
zq
,
dq
}
=
res
.
data
tableData
.
value
=
[...
zq
,
...
dq
]
}
else
{
// 合并城市经理结构为扁平化
tableData
.
value
=
res
.
data
}
isLoading
.
value
=
false
}
const
isDaQuZQ
=
proxy
.
checkPermi
([
'promotion:dashboard:list-show'
])
getTableList
(
isDaQuZQ
?
'大区战区-分析'
:
'城市经理-分析'
)
</
script
>
src/views/mobile/pages/storeExecution/dashboard/tabs/schedule_dis.vue
0 → 100644
浏览文件 @
6bf26d6d
<
template
>
<!-- 档期陈列 -->
<el-form
:inline=
"true"
:model=
"queryParams"
class=
"demo-form-inline"
>
<el-form-item
label=
"计划月份"
>
<el-date-picker
v-model=
"queryParams.salesMonth"
type=
"month"
placeholder=
"选择计划月份"
@
change=
"getTableList"
clearable
/>
</el-form-item>
</el-form>
<CustomTable
:tableData=
"tableData"
:baseColumns=
"baseColumns"
:isLoading=
"isLoading"
@
getTableList=
"getTableList"
@
updateShowSearch=
"v => showSearch.value = v"
/>
</
template
>
<
script
setup
lang=
"jsx"
>
import
CustomTable
from
'../components/Table'
import
{
getDisplayScheduleDashboardList
,
getDisplayScheduleDashboardListArea
}
from
'@/api'
import
{
parseTime
}
from
'@/utils'
import
{
getScheduleDisConfig
}
from
'./data'
/*************** 表格数据 ***************/
// 提交变更
const
submitChange
=
async
(
row
,
col
)
=>
{
// 需要特殊处理的
// 1. 实际主货架-形式,为空时,置空实际主货架-数量
if
(
col
.
prop
===
'actualMainShelfType'
&&
!
row
.
actualMainShelfType
)
{
row
.
actualMainShelfQty
=
0
}
// 关联的公式计算列,需要特殊处理
for
(
const
str
of
col
.
requestKey
)
{
const
obj
=
getScheduleDisConfig
().
flatMap
(
item
=>
{
if
(
item
.
children
)
{
return
item
.
children
.
filter
(
child
=>
!
child
.
onlyFill
);
}
return
[];
}).
find
(
item
=>
item
.
prop
===
str
)
if
(
obj
&&
obj
.
type
===
'formula'
)
{
obj
.
func
(
row
)
}
}
await
submitDisplayScheduleDetail
({
id
:
row
.
sapdId
,
[
col
.
prop
]:
row
[
col
.
prop
],
// 当前修改列的值
...
col
.
requestKey
.
reduce
((
acc
,
key
)
=>
({
...
acc
,
[
key
]:
row
[
key
]
}),
{}),
// 额外携带影响的列字段值
// 特殊类型字段处理
// 端架数量实际
actualEndCapQty
:
row
.
actualEndCapQty
||
0
,
// 地堆平米数实际
actualFloorStackArea
:
row
.
actualFloorStackArea
||
0
,
})
}
// 全部列
const
baseColumns
=
ref
(
getScheduleDisConfig
(
submitChange
));
// 表格数据
const
queryParams
=
reactive
({
salesMonth
:
new
Date
(),
})
const
tableData
=
ref
([])
const
isLoading
=
ref
(
true
)
const
total
=
ref
(
0
)
// 筛选列表数据
const
getTableList
=
async
(
operation
)
=>
{
isLoading
.
value
=
true
const
res
=
await
(
operation
===
'大区战区-分析'
?
getDisplayScheduleDashboardList
:
getDisplayScheduleDashboardListArea
)({
...
queryParams
,
salesMonth
:
parseTime
(
queryParams
.
salesMonth
,
'{y}-{m}'
)
})
if
(
operation
===
'大区战区-分析'
)
{
// 合并战区大区结构为扁平化
const
{
zq
,
dq
}
=
res
.
data
tableData
.
value
=
[...
zq
,
...
dq
]
}
else
{
// 合并城市经理结构为扁平化
tableData
.
value
=
res
.
data
}
isLoading
.
value
=
false
}
const
{
proxy
}
=
getCurrentInstance
()
const
isDaQuZQ
=
proxy
.
checkPermi
([
'promotion:dashboard:list-show'
])
getTableList
(
isDaQuZQ
?
'大区战区-分析'
:
'城市经理-分析'
)
</
script
>
\ No newline at end of file
src/views/mobile/pages/storeExecution/dashboard/tabs/six_little_diamonds.vue
0 → 100644
浏览文件 @
6bf26d6d
<
template
>
<!-- 六小金刚 -->
<el-form
:inline=
"true"
:model=
"queryParams"
class=
"demo-form-inline"
>
<el-form-item
label=
"计划月份"
>
<el-date-picker
v-model=
"queryParams.salesMonth"
type=
"month"
placeholder=
"选择计划月份"
@
change=
"getTableList"
clearable
/>
</el-form-item>
</el-form>
<CustomTable
:tableData=
"tableData"
:baseColumns=
"baseColumns"
:isLoading=
"isLoading"
@
getTableList=
"getTableList"
@
updateShowSearch=
"v => showSearch.value = v"
/>
</
template
>
<
script
setup
lang=
"jsx"
>
import
CustomTable
from
'../components/Table'
import
{
getDisplayScheduleDashboardList
,
getDisplayScheduleDashboardListArea
}
from
'@/api'
import
{
getSixLittleDiamondsConfig
}
from
'./data.jsx'
import
{
parseTime
}
from
'@/utils'
const
{
proxy
}
=
getCurrentInstance
()
/*************** 搜索列表 ***************/
const
showSearch
=
ref
(
true
)
/*************** 表格 ***************/
// 提交变更
const
submitChange
=
async
(
row
,
col
)
=>
{
let
requestObj
=
{}
if
(
col
.
requestKey
)
{
// 关联的公式计算列,需要特殊处理
for
(
const
str
of
col
.
requestKey
)
{
const
obj
=
getSixLittleDiamondsConfig
().
flatMap
(
item
=>
{
if
(
item
.
children
)
{
return
item
.
children
.
filter
(
child
=>
!
child
.
onlyFill
);
}
return
[];
}).
find
(
item
=>
item
.
prop
===
str
)
if
(
obj
&&
obj
.
type
===
'formula'
)
{
obj
.
func
(
row
)
}
}
requestObj
=
col
.
requestKey
.
reduce
((
acc
,
key
)
=>
({
...
acc
,
[
key
]:
row
[
key
]
}),
{})
}
await
submitSixLittleDiamondsPlan
({
id
:
row
.
sadjId
,
[
col
.
prop
]:
row
[
col
.
prop
],
// 当前修改列的值
...
requestObj
})
}
// 全部列
const
baseColumns
=
ref
(
getSixLittleDiamondsConfig
(
submitChange
));
// 表格数据
const
queryParams
=
reactive
({
salesMonth
:
new
Date
(),
})
const
tableData
=
ref
([])
const
isLoading
=
ref
(
true
)
const
total
=
ref
(
0
)
// 筛选列表数据
const
getTableList
=
async
(
operation
)
=>
{
isLoading
.
value
=
true
const
res
=
await
(
operation
===
'大区战区-分析'
?
getDisplayScheduleDashboardList
:
getDisplayScheduleDashboardListArea
)({
...
queryParams
,
salesMonth
:
parseTime
(
queryParams
.
salesMonth
,
'{y}-{m}'
)
})
if
(
operation
===
'大区战区-分析'
)
{
// 合并战区大区结构为扁平化
const
{
zq
,
dq
}
=
res
.
data
tableData
.
value
=
[...
zq
,
...
dq
]
}
else
{
// 合并城市经理结构为扁平化
tableData
.
value
=
res
.
data
}
isLoading
.
value
=
false
}
const
isDaQuZQ
=
proxy
.
checkPermi
([
'promotion:dashboard:list-show'
])
getTableList
(
isDaQuZQ
?
'大区战区-分析'
:
'城市经理-分析'
)
</
script
>
<
style
scoped
></
style
>
\ No newline at end of file
src/views/mobile/pages/storeExecution/dashboard/tabs/snack.vue
0 → 100644
浏览文件 @
6bf26d6d
<
template
>
<!-- 零食陈列 -->
<el-form
:inline=
"true"
:model=
"queryParams"
class=
"demo-form-inline"
>
<el-form-item
label=
"计划月份"
>
<el-date-picker
v-model=
"queryParams.salesMonth"
type=
"month"
placeholder=
"选择计划月份"
@
change=
"getTableList"
clearable
/>
</el-form-item>
</el-form>
<CustomTable
:tableData=
"tableData"
:baseColumns=
"baseColumns"
:isLoading=
"isLoading"
@
getTableList=
"getTableList"
@
updateShowSearch=
"v => showSearch.value = v"
/>
</
template
>
<
script
setup
lang=
"jsx"
>
import
CustomTable
from
'../components/Table'
import
{
getDisplayScheduleDashboardList
,
getDisplayScheduleDashboardListArea
}
from
'@/api'
import
{
parseTime
}
from
'@/utils'
import
{
getSnackCofing
}
from
'./data.jsx'
;
/*************** 操作类型 ***************/
// 提交变更
const
submitChange
=
async
(
row
,
col
)
=>
{
// 需要特殊处理的
// 1. 实际主货架-形式,为空时,置空实际主货架-数量
// if (col.prop === 'actualMainShelfType' && !row.actualMainShelfType) {
// row.actualMainShelfQty = 0
// }
// 关联的公式计算列,需要特殊处理
for
(
const
str
of
col
.
requestKey
)
{
const
obj
=
getSnackCofing
().
flatMap
(
item
=>
{
if
(
item
.
children
)
{
return
item
.
children
.
filter
(
child
=>
!
child
.
onlyFill
);
}
return
[];
}).
find
(
item
=>
item
.
prop
===
str
)
if
(
obj
&&
obj
.
type
===
'formula'
)
{
obj
.
func
(
row
)
}
}
await
submitSnackPlan
({
id
:
row
.
sasdId
,
[
col
.
prop
]:
row
[
col
.
prop
],
// 当前修改列的值
...
col
.
requestKey
.
reduce
((
acc
,
key
)
=>
({
...
acc
,
[
key
]:
row
[
key
]
}),
{}),
// 额外携带影响的列字段值
})
}
// 全部列
const
baseColumns
=
ref
(
getSnackCofing
(
submitChange
));
// 表格数据
const
queryParams
=
reactive
({
salesMonth
:
new
Date
(),
})
const
tableData
=
ref
([])
const
isLoading
=
ref
(
true
)
const
total
=
ref
(
0
)
// 筛选列表数据
const
getTableList
=
async
(
operation
)
=>
{
isLoading
.
value
=
true
const
res
=
await
(
operation
===
'大区战区-分析'
?
getDisplayScheduleDashboardList
:
getDisplayScheduleDashboardListArea
)({
...
queryParams
,
salesMonth
:
parseTime
(
queryParams
.
salesMonth
,
'{y}-{m}'
)
})
if
(
operation
===
'大区战区-分析'
)
{
// 合并战区大区结构为扁平化
const
{
zq
,
dq
}
=
res
.
data
tableData
.
value
=
[...
zq
,
...
dq
]
}
else
{
// 合并城市经理结构为扁平化
tableData
.
value
=
res
.
data
}
isLoading
.
value
=
false
}
const
{
proxy
}
=
getCurrentInstance
()
const
isDaQuZQ
=
proxy
.
checkPermi
([
'promotion:dashboard:list-show'
])
getTableList
(
isDaQuZQ
?
'大区战区-分析'
:
'城市经理-分析'
)
</
script
>
<
style
scoped
lang=
"scss"
>
.container
{
.el-tabs
{
height
:
100%
;
display
:
flex
;
flex-direction
:
column-reverse
;
.el-tabs__content
{
display
:
flex
;
flex-direction
:
column
;
height
:
100%
;
.el-tab-pane
{
height
:
100%
;
display
:
flex
;
flex-direction
:
column
;
.pagination-container
{
margin
:
10px
;
}
}
.formula-column
{
display
:
flex
;
justify-content
:
center
;
align-items
:
center
;
.el-icon
{
margin-left
:
2px
;
}
}
}
}
.el-form-item
{
align-items
:
center
;
}
/* 表格区域 */
.auto-fit-header-table
{
/* 优化超长文本的显示效果 */
.cell
{
/* padding: 0 .2133rem; */
}
::v-deep
(
.el-table__row
)
{
.el-table__cell
{
padding
:
0
;
}
}
::v-deep
(
.column-style
)
{
.cell-style
{
/* margin: 0 -12px; */
>
div
{
display
:
flex
;
flex-direction
:
column
;
align-items
:
flex-start
;
>
span
{
text-align
:
left
;
text-indent
:
5px
;
display
:
inline-block
;
width
:
100%
;
background-color
:
#e1e2e6
;
border-bottom
:
1px
solid
#ebeef5
;
}
}
/* 表格内下拉框 */
.el-select
{
width
:
100%
!
important
;
padding
:
10px
;
}
.el-input
{
padding
:
10px
;
}
}
}
}
}
</
style
>
\ No newline at end of file
src/views/mobile/pages/storeExecution/dashboard/tabs/three_two_seconds.vue
0 → 100644
浏览文件 @
6bf26d6d
<
template
>
<!-- 三米两秒 -->
<el-form
:inline=
"true"
:model=
"queryParams"
class=
"demo-form-inline"
>
<el-form-item
label=
"计划月份"
>
<el-date-picker
v-model=
"queryParams.salesMonth"
type=
"month"
placeholder=
"选择计划月份"
@
change=
"getTableList"
clearable
/>
</el-form-item>
</el-form>
<CustomTable
:tableData=
"tableData"
:baseColumns=
"baseColumns"
:isLoading=
"isLoading"
@
getTableList=
"getTableList"
@
updateShowSearch=
"v => showSearch.value = v"
/>
</
template
>
<
script
setup
lang=
"jsx"
>
import
CustomTable
from
'../components/Table'
import
{
getDisplayScheduleDashboardList
,
getDisplayScheduleDashboardListArea
}
from
'@/api'
import
{
getThreeTwoSecondsConfig
}
from
'./data.jsx'
import
{
parseTime
}
from
'@/utils'
const
{
proxy
}
=
getCurrentInstance
()
/*************** 搜索列表 ***************/
const
showSearch
=
ref
(
true
)
/*************** 表格 ***************/
// 提交变更
const
submitChange
=
async
(
row
,
col
)
=>
{
let
requestObj
=
{}
if
(
col
.
requestKey
)
{
// 关联的公式计算列,需要特殊处理
for
(
const
str
of
col
.
requestKey
)
{
const
obj
=
getThreeTwoSecondsConfig
().
flatMap
(
item
=>
{
if
(
item
.
children
)
{
return
item
.
children
.
filter
(
child
=>
!
child
.
onlyFill
);
}
return
[];
}).
find
(
item
=>
item
.
prop
===
str
)
if
(
obj
&&
obj
.
type
===
'formula'
)
{
obj
.
func
(
row
)
}
}
requestObj
=
col
.
requestKey
.
reduce
((
acc
,
key
)
=>
({
...
acc
,
[
key
]:
row
[
key
]
}),
{})
}
await
submitThreeMetersTwoSecondsPlan
({
id
:
row
.
sadsId
,
[
col
.
prop
]:
row
[
col
.
prop
],
// 当前修改列的值
...
requestObj
})
}
// 全部列
const
baseColumns
=
ref
(
getThreeTwoSecondsConfig
(
submitChange
));
// 表格数据
const
queryParams
=
reactive
({
salesMonth
:
new
Date
(),
})
const
tableData
=
ref
([])
const
isLoading
=
ref
(
true
)
const
total
=
ref
(
0
)
// 筛选列表数据
const
getTableList
=
async
(
operation
)
=>
{
isLoading
.
value
=
true
const
res
=
await
(
operation
===
'大区战区-分析'
?
getDisplayScheduleDashboardList
:
getDisplayScheduleDashboardListArea
)({
...
queryParams
,
salesMonth
:
parseTime
(
queryParams
.
salesMonth
,
'{y}-{m}'
)
})
if
(
operation
===
'大区战区-分析'
)
{
// 合并战区大区结构为扁平化
const
{
zq
,
dq
}
=
res
.
data
tableData
.
value
=
[...
zq
,
...
dq
]
}
else
{
// 合并城市经理结构为扁平化
tableData
.
value
=
res
.
data
}
isLoading
.
value
=
false
}
const
isDaQuZQ
=
proxy
.
checkPermi
([
'promotion:dashboard:list-show'
])
getTableList
(
isDaQuZQ
?
'大区战区-分析'
:
'城市经理-分析'
)
</
script
>
<
style
scoped
></
style
>
\ No newline at end of file
src/views/mobile/pages/storeExecution/report/components/SearchList/index.vue
0 → 100644
浏览文件 @
6bf26d6d
<
template
>
<!-- 抽屉搜索组件 -->
<van-popup
v-model:show=
"showDrawer"
position=
"right"
class=
"search-drawer"
:style=
"
{ width: '85%', height: '100%' }"
teleport="body"
@close="handleClose">
<!-- 抽屉头部 -->
<van-nav-bar
title=
"筛选条件"
left-text=
"关闭"
left-arrow
@
click-left=
"handleClose"
/>
<!-- 搜索表单内容 -->
<div
class=
"search-content"
>
<van-cell-group
inset
>
<!-- 计划月份 -->
<van-field
:modelValue=
"parseTime(queryParams.salesMonth, '
{y}-{m}')"
label="计划月份"
placeholder="选择计划月份"
readonly
is-link
@click="showMonthPicker = true">
<template
#
input
>
<span>
{{
parseTime
(
queryParams
.
salesMonth
,
'{y
}
-{m
}
'
)
||
'请选择'
}}
<
/span
>
<
/template
>
<
/van-field
>
<!--
大区
/
战区
-->
<
van
-
field
v
-
model
=
"queryParams.deptName"
label
=
"大区/战区"
placeholder
=
"请输入大区/战区"
@
update
:
model
-
value
=
"handleChange"
clearable
/>
<!--
经销商编码
/
名称
-->
<
van
-
field
v
-
model
=
"queryParams.dealerCN"
label
=
"经销商编码/名称"
placeholder
=
"请输入经销商编码/名称"
@
update
:
model
-
value
=
"handleChange"
clearable
/>
<!--
系统名称
-->
<
van
-
field
v
-
model
=
"queryParams.lineNameLike"
label
=
"系统名称"
placeholder
=
"请输入系统名称"
@
update
:
model
-
value
=
"handleChange"
clearable
/>
<!--
门店编码
/
名称
-->
<
van
-
field
v
-
if
=
"showStoreSearch"
v
-
model
=
"queryParams.storeCN"
label
=
"门店编码/名称"
placeholder
=
"请输入门店编码/名称"
@
update
:
model
-
value
=
"handleChange"
clearable
/>
<!--
数据筛选
-->
<
van
-
field
v
-
model
=
"queryParams.rqStatus"
label
=
"数据筛选"
placeholder
=
"请选择筛选状态"
readonly
is
-
link
@
click
=
"showStatusPicker = true"
>
<
template
#
input
>
<
span
>
{{
getStatusText
(
queryParams
.
rqStatus
)
}}
<
/span
>
<
/template
>
<
/van-field
>
<
/van-cell-group
>
<!--
月份选择器
-->
<
van
-
popup
v
-
model
:
show
=
"showMonthPicker"
position
=
"bottom"
teleport
=
"body"
>
<
van
-
date
-
picker
v
-
model
=
"currentMonth"
title
=
"选择计划月份"
:
columns
-
type
=
"['year', 'month']"
:
min
-
date
=
"minDate"
:
max
-
date
=
"maxDate"
@
confirm
=
"confirmMonth"
@
cancel
=
"showMonthPicker = false"
/>
<
/van-popup
>
<!--
状态选择器
-->
<
van
-
popup
v
-
model
:
show
=
"showStatusPicker"
position
=
"bottom"
teleport
=
"body"
>
<
van
-
picker
:
columns
=
"statusOptions"
@
confirm
=
"confirmStatus"
@
cancel
=
"showStatusPicker = false"
/>
<
/van-popup
>
<!--
操作按钮
-->
<
div
class
=
"action-buttons"
>
<
van
-
button
type
=
"default"
size
=
"large"
@
click
=
"handleReset"
class
=
"reset-btn"
>
<
van
-
icon
name
=
"replay"
/>
重置
<
/van-button
>
<
van
-
button
type
=
"primary"
size
=
"large"
@
click
=
"handleConfirm"
class
=
"confirm-btn"
>
<
van
-
icon
name
=
"success"
/>
确定
<
/van-button
>
<
/div
>
<
/div
>
<
/van-popup
>
<
/template
>
<
script
setup
>
import
{
ref
,
computed
,
watch
}
from
'vue'
import
{
parseTime
}
from
'@/utils'
const
{
proxy
}
=
getCurrentInstance
()
const
props
=
defineProps
({
showSearch
:
{
type
:
Boolean
,
default
:
false
}
,
showStoreSearch
:
{
type
:
Boolean
,
default
:
true
}
,
queryParams
:
{
type
:
Object
,
default
:
()
=>
({
}
)
}
}
)
const
emits
=
defineEmits
([
'change'
,
'update:showSearch'
])
// 抽屉显示状态
const
showDrawer
=
computed
({
get
:
()
=>
props
.
showSearch
,
set
:
(
value
)
=>
emits
(
'update:showSearch'
,
value
)
}
)
// 选择器状态
const
showMonthPicker
=
ref
(
false
)
const
showStatusPicker
=
ref
(
false
)
const
currentMonth
=
ref
([])
// 日期范围
const
minDate
=
new
Date
(
2016
,
0
,
1
)
const
maxDate
=
new
Date
(
new
Date
().
getFullYear
(),
new
Date
().
getMonth
()
+
1
,
31
)
// 状态选项
const
statusOptions
=
[
{
text
:
'全部'
,
value
:
''
}
,
{
text
:
'未执行'
,
value
:
'未执行'
}
]
// 获取状态文本
const
getStatusText
=
(
value
)
=>
{
const
option
=
statusOptions
.
find
(
item
=>
item
.
value
===
value
)
return
option
?
option
.
text
:
'全部'
}
// 确认月份选择
const
confirmMonth
=
({
selectedValues
:
value
}
)
=>
{
// value 是 [2025, 2] 这种格式
const
year
=
value
[
0
]
const
month
=
String
(
value
[
1
]).
padStart
(
2
,
'0'
)
props
.
queryParams
.
salesMonth
=
new
Date
(
`${year
}
-${month
}
-01`
)
showMonthPicker
.
value
=
false
handleChange
()
}
// 确认状态选择
const
confirmStatus
=
(
value
)
=>
{
props
.
queryParams
.
rqStatus
=
value
.
selectedOptions
[
0
]?.
value
||
''
showStatusPicker
.
value
=
false
handleChange
()
}
// 处理变化
const
handleChange
=
()
=>
{
emits
(
'change'
)
}
// 关闭抽屉
const
handleClose
=
()
=>
{
showDrawer
.
value
=
false
}
// 重置表单
const
handleReset
=
()
=>
{
// 重置所有查询参数
Object
.
keys
(
props
.
queryParams
).
forEach
(
key
=>
{
if
(
key
!==
'pageNum'
&&
key
!==
'pageSize'
)
{
props
.
queryParams
[
key
]
=
''
}
}
)
handleChange
()
}
// 确定搜索
const
handleConfirm
=
()
=>
{
handleChange
()
handleClose
()
}
// 监听外部showSearch变化
watch
(()
=>
props
.
showSearch
,
(
newVal
)
=>
{
if
(
newVal
)
{
// 打开抽屉时初始化当前月份
if
(
props
.
queryParams
.
salesMonth
)
{
// 如果是日期类型转成字符串
const
[
year
,
month
]
=
props
.
queryParams
.
salesMonth
.
toISOString
().
split
(
'T'
)[
0
].
substring
(
0
,
7
).
split
(
'-'
)
// currentMonth = [2025, 02] 这种格式
currentMonth
.
value
=
[
parseInt
(
year
),
parseInt
(
month
)]
}
else
{
// 当前年月日,注意:getMonth()返回0-11,需要+1变成1-12
const
now
=
new
Date
()
currentMonth
.
value
=
[
now
.
getFullYear
(),
now
.
getMonth
()
+
1
]
}
}
}
)
<
/script
>
<
style
scoped
lang
=
"scss"
>
.
search
-
drawer
{
.
search
-
content
{
height
:
calc
(
100
%
-
46
px
);
// 减去导航栏高度
overflow
-
y
:
auto
;
padding
:
16
px
;
.
van
-
cell
-
group
{
margin
-
bottom
:
20
px
;
}
.
action
-
buttons
{
position
:
fixed
;
bottom
:
0
;
left
:
0
;
right
:
0
;
background
:
#
fff
;
padding
:
16
px
;
display
:
flex
;
gap
:
12
px
;
border
-
top
:
1
px
solid
#
ebedf0
;
.
reset
-
btn
,
.
confirm
-
btn
{
flex
:
1
;
:
deep
(.
van
-
button__content
)
{
display
:
flex
;
align
-
items
:
center
;
gap
:
4
px
;
}
}
}
}
}
<
/style>
\ No newline at end of file
src/views/mobile/pages/storeExecution/report/components/Table/index.vue
0 → 100644
浏览文件 @
6bf26d6d
差异被折叠。
点击展开。
src/views/mobile/pages/storeExecution/report/index.vue
0 → 100644
浏览文件 @
6bf26d6d
<
template
>
<div
class=
"app-container"
>
<div
class=
"container"
>
<van-nav-bar
fixed
left-arrow
@
click-left=
"router.back()"
title=
"店内执行上报浏览"
right-text=
"筛选"
@
click-right=
"handleClickRight"
/>
<SearchList
v-model:showSearch=
"showSearch"
:queryParams=
"params"
@
change=
"getTableList"
/>
<el-tabs
v-model=
"activeName"
class=
"demo-tabs"
@
tab-click=
"handleClickTabs"
>
<el-tab-pane
label=
"常规陈列"
name=
"常规陈列"
>
<Display
:params=
"params"
ref=
"display"
/>
</el-tab-pane>
<el-tab-pane
label=
"档期计划"
name=
"档期计划"
>
<Schedule
:params=
"params"
ref=
"schedule"
/>
</el-tab-pane>
<el-tab-pane
label=
"档期陈列"
name=
"档期陈列"
>
<ScheduleDis
:params=
"params"
ref=
"scheduleDis"
/>
</el-tab-pane>
<el-tab-pane
label=
"零食陈列"
name=
"零食陈列"
>
<Snack
:params=
"params"
ref=
"snack"
/>
</el-tab-pane>
<el-tab-pane
label=
"三米两秒"
name=
"三米两秒"
>
<ThreeTwoSeconds
:params=
"params"
ref=
"threeTwoSeconds"
/>
</el-tab-pane>
<el-tab-pane
label=
"六小金刚"
name=
"六小金刚"
>
<SixLittleDiamonds
:params=
"params"
ref=
"sixLittleDiamonds"
/>
</el-tab-pane>
</el-tabs>
</div>
</div>
</
template
>
<
script
setup
>
import
Display
from
'./tabs/display.vue'
import
Schedule
from
'./tabs/schedule.vue'
import
ScheduleDis
from
'./tabs/schedule_dis.vue'
import
Snack
from
'./tabs/snack.vue'
import
ThreeTwoSeconds
from
'./tabs/three_two_seconds.vue'
import
SixLittleDiamonds
from
'./tabs/six_little_diamonds.vue'
import
SearchList
from
'./components/SearchList'
const
router
=
useRouter
()
const
activeName
=
ref
(
'常规陈列'
);
const
handleClickTabs
=
(
tab
)
=>
{
activeName
.
value
=
tab
.
name
;
}
const
showSearch
=
ref
(
false
)
const
handleClickRight
=
()
=>
{
showSearch
.
value
=
true
;
}
const
params
=
ref
({
pageNum
:
1
,
pageSize
:
20
,
salesMonth
:
new
Date
(),
deptName
:
''
,
dealerCN
:
''
,
lineNameLike
:
''
,
storeCN
:
''
})
const
display
=
ref
(
null
)
const
schedule
=
ref
(
null
)
const
scheduleDis
=
ref
(
null
)
const
snack
=
ref
(
null
)
const
threeTwoSeconds
=
ref
(
null
)
const
sixLittleDiamonds
=
ref
(
null
)
const
getTableList
=
()
=>
{
display
.
value
.
getTableList
()
schedule
.
value
.
getTableList
()
scheduleDis
.
value
.
getTableList
()
snack
.
value
.
getTableList
()
threeTwoSeconds
.
value
.
getTableList
()
sixLittleDiamonds
.
value
.
getTableList
()
}
</
script
>
<
style
scoped
lang=
"scss"
>
.app-container
{
padding
:
10px
;
padding-top
:
46px
;
.container
{
padding
:
0px
;
.el-tabs
{
height
:
100%
;
display
:
flex
;
flex-direction
:
column-reverse
;
::v-deep
(
.el-tabs__header
)
{
// 确保底部边框线完整显示
border-bottom
:
1px
solid
var
(
--
el-border-color-light
);
width
:
100%
;
}
::v-deep
(
.el-tabs__nav-wrap
)
{
overflow-x
:
auto
;
overflow-y
:
hidden
;
-webkit-overflow-scrolling
:
touch
;
// iOS平滑滚动
scrollbar-width
:
none
;
// Firefox隐藏滚动条
&
:
:
after
{
// 隐藏el-tabs默认的底部伪元素边框
display
:
none
;
}
&
:
:-
webkit-scrollbar
{
display
:
none
;
// Chrome/Safari隐藏滚动条
}
}
::v-deep
(
.el-tabs__nav-scroll
)
{
overflow
:
visible
;
width
:
max-content
;
}
::v-deep
(
.el-tabs__content
)
{
display
:
flex
;
flex-direction
:
column
;
overflow-y
:
scroll
;
// height: 100%;
.el-tab-pane
{
// height: 100%;
display
:
flex
;
flex-direction
:
column
;
}
}
}
}
}
</
style
>
\ No newline at end of file
src/views/mobile/pages/storeExecution/report/tabs/data.jsx
0 → 100644
浏览文件 @
6bf26d6d
This source diff could not be displayed because it is too large. You can
view the blob
instead.
src/views/mobile/pages/storeExecution/report/tabs/display.vue
0 → 100644
浏览文件 @
6bf26d6d
差异被折叠。
点击展开。
src/views/mobile/pages/storeExecution/report/tabs/schedule.vue
0 → 100644
浏览文件 @
6bf26d6d
差异被折叠。
点击展开。
src/views/mobile/pages/storeExecution/report/tabs/schedule_dis.vue
0 → 100644
浏览文件 @
6bf26d6d
差异被折叠。
点击展开。
src/views/mobile/pages/storeExecution/report/tabs/six_little_diamonds.vue
0 → 100644
浏览文件 @
6bf26d6d
差异被折叠。
点击展开。
src/views/mobile/pages/storeExecution/report/tabs/snack.vue
0 → 100644
浏览文件 @
6bf26d6d
差异被折叠。
点击展开。
src/views/mobile/pages/storeExecution/report/tabs/three_two_seconds.vue
0 → 100644
浏览文件 @
6bf26d6d
差异被折叠。
点击展开。
src/views/promotion/display_schedule/components/SearchList/index.vue
浏览文件 @
6bf26d6d
差异被折叠。
点击展开。
src/views/promotion/display_schedule/components/Table/index.vue
浏览文件 @
6bf26d6d
差异被折叠。
点击展开。
src/views/promotion/display_schedule/tabs/data.jsx
浏览文件 @
6bf26d6d
差异被折叠。
点击展开。
src/views/promotion/display_schedule/tabs/display.vue
浏览文件 @
6bf26d6d
差异被折叠。
点击展开。
src/views/promotion/display_schedule/tabs/schedule.vue
浏览文件 @
6bf26d6d
差异被折叠。
点击展开。
src/views/promotion/display_schedule/tabs/schedule_dis.vue
浏览文件 @
6bf26d6d
差异被折叠。
点击展开。
src/views/promotion/display_schedule/tabs/six_little_diamonds.vue
浏览文件 @
6bf26d6d
差异被折叠。
点击展开。
src/views/promotion/display_schedule/tabs/snack.vue
浏览文件 @
6bf26d6d
差异被折叠。
点击展开。
src/views/promotion/display_schedule/tabs/three_two_seconds.vue
浏览文件 @
6bf26d6d
差异被折叠。
点击展开。
src/views/promotion/display_schedule_dashboard/components/Table/index.vue
浏览文件 @
6bf26d6d
差异被折叠。
点击展开。
src/views/promotion/display_schedule_dashboard/tabs/data.jsx
浏览文件 @
6bf26d6d
差异被折叠。
点击展开。
src/views/promotion/display_schedule_dashboard/tabs/display.vue
浏览文件 @
6bf26d6d
差异被折叠。
点击展开。
src/views/promotion/display_schedule_dashboard/tabs/schedule.vue
浏览文件 @
6bf26d6d
差异被折叠。
点击展开。
src/views/promotion/display_schedule_dashboard/tabs/schedule_dis.vue
浏览文件 @
6bf26d6d
差异被折叠。
点击展开。
src/views/promotion/display_schedule_dashboard/tabs/six_little_diamonds.vue
浏览文件 @
6bf26d6d
差异被折叠。
点击展开。
src/views/promotion/display_schedule_dashboard/tabs/snack.vue
浏览文件 @
6bf26d6d
差异被折叠。
点击展开。
src/views/promotion/display_schedule_dashboard/tabs/three_two_seconds.vue
浏览文件 @
6bf26d6d
差异被折叠。
点击展开。
src/views/promotion/plan/effectivePlan.vue
浏览文件 @
6bf26d6d
差异被折叠。
点击展开。
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论