提交 abe6210f authored 作者: lidongxu's avatar lidongxu

refactor(promotion): 促销计划_拆分单独组件过程中

上级 a50fd001
<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="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>
</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 { parseTime } from '@/utils'
import { ElMessage, ElMessageBox } from 'element-plus';
import EffectivePlan from './effectivePlan.vue';
const { proxy } = getCurrentInstance();
const isCityManager = userStore().promotionIdentity
const { recentPickerOptions: pickerOptions } = useDatePickerOptions()
const queryParams = reactive({
activityDate: [],
planStatus: '',
region: '全国',
provinceId: '',
cityId: '',
zoneId: '', // 经销商
warzoneId: '', // 战区
employeeId: '', // 归属人
storeName: '', // 门店名称
pageNum: 1,
pageSize: 10,
})
const taskStatusList = ref(Object.values(PROMOTION_STATUS))
// 区域查询切换
const provinceList = ref([])
const cityList = ref([])
// 获取省份和城市列表
const getProCity = async () => {
const { data } = await getProCityAPI(queryParams)
// 本次省份里有值,证明 data 是城市数据
if (queryParams.provinceId) {
queryParams.cityId = ''
cityList.value = data.map(item => ({
label: item.name,
value: item.num
}))
} else {
// 省份列表数据
queryParams.cityId = ''
cityList.value = []
provinceList.value = data.map(item => ({
label: item.name,
value: item.num
}))
}
getPlanList()
}
// 切换
const regionChange = (val) => {
if (val === '全国') {
queryParams.provinceId = ''
queryParams.cityId = ''
} else if (val === '省') {
queryParams.cityId = ''
} else if (val === '省-市') {
cityList.value = []
getProCity()
}
getPlanList()
}
// 查询经销商列表
const zoneList = ref([])
const getZoneList = async () => {
const { data } = await getDealerListAPI(queryParams)
zoneList.value = data.map(item => {
return {
label: item.dealerName,
value: item.dealerId
}
})
}
// 经销商远程搜索(点击输入框自动触发)
const zoneRemoteSearch = (query) => {
queryParams.dealerName = query
getZoneList()
}
// 查询战区列表
const warZoneList = ref([])
const getWarZoneList = async () => {
const { data } = await getWarZoneListAPI()
warZoneList.value = data.map(item => {
return {
label: item.orgName,
value: item.qcId
}
})
}
// 查询归属人列表
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
}
})
}
// 表格复选框的数据
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
// }
}
// 任务列表
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) {
// 城市经理 (用员工 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 ? 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) {
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) {
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 () => {
await getBelongPerList()
getPlanList() // 任务列表需要当前归属人 id,所以保证上一步网络请求完成
getProCity()
getWarZoneList()
};
init()
</script>
<style scoped>
.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
...@@ -127,342 +127,34 @@ ...@@ -127,342 +127,34 @@
</el-form-item> </el-form-item>
</el-row> </el-row>
</el-form> </el-form>
<el-row :gutter="10" <el-tabs type="card">
class="mb8" <el-tab-pane label="有效计划">
justify="space-between"> <EffectivePlan />
<el-col :span="1.5"> </el-tab-pane>
<el-button type="danger" <el-tab-pane label="已删除计划">Config</el-tab-pane>
plain </el-tabs>
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>
</div> </div>
</div> </div>
</template> </template>
<script setup> <script setup>
import { v4 as uuidv4 } from 'uuid';
import { getPlanListAPI, uploadFileToOSSAPI, addPlanAPI, savePlanAPI, deletePlanAPI, addPlanByRoleAPI, getProCityAPI, getDealerListAPI, getWarZoneListAPI, getChargeListAPI, addPlanByWebAPI, updatePlanByWebAPI, getPlanStoreListAPI, updatePlanAPI, batchUpdatePlanAPI } from '@/api' import { getPlanListAPI, uploadFileToOSSAPI, addPlanAPI, savePlanAPI, deletePlanAPI, addPlanByRoleAPI, getProCityAPI, getDealerListAPI, getWarZoneListAPI, getChargeListAPI, addPlanByWebAPI, updatePlanByWebAPI, getPlanStoreListAPI, updatePlanAPI, batchUpdatePlanAPI } from '@/api'
import { useDatePickerOptions, checkPlanExpire } from '@/hooks' import { useDatePickerOptions, checkPlanExpire } from '@/hooks'
import { v4 as uuidv4 } from 'uuid';
import store from '@/store' import store from '@/store'
import userStore from '@/store/modules/user' import userStore from '@/store/modules/user'
import { getPromotionActiveStatus } from '@/dicts' import { PROMOTION_STATUS, getPromotionActiveStatus } from '@/dicts'
import { PROMOTION_STATUS } from '@/dicts'
import { parseTime } from '@/utils' import { parseTime } from '@/utils'
import { ElMessage, ElMessageBox } from 'element-plus'; import EffectivePlan from './effectivePlan.vue';
const { proxy } = getCurrentInstance(); const { proxy } = getCurrentInstance();
const isCityManager = ref(userStore().promotionIdentity)
const isCityManager = userStore().promotionIdentity
const { recentPickerOptions: pickerOptions } = useDatePickerOptions() const { recentPickerOptions: pickerOptions } = useDatePickerOptions()
const taskStatusList = ref(Object.values(PROMOTION_STATUS))
const queryParams = reactive({ const queryParams = reactive({
activityDate: [], activityDate: [],
planStatus: '', planStatus: '',
...@@ -476,7 +168,7 @@ const queryParams = reactive({ ...@@ -476,7 +168,7 @@ const queryParams = reactive({
pageNum: 1, pageNum: 1,
pageSize: 10, pageSize: 10,
}) })
const taskStatusList = ref(Object.values(PROMOTION_STATUS))
// 区域查询切换 // 区域查询切换
const provinceList = ref([]) const provinceList = ref([])
...@@ -561,692 +253,6 @@ const getBelongPerList = async () => { ...@@ -561,692 +253,6 @@ const getBelongPerList = async () => {
}) })
} }
// 表格复选框的数据
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
// }
}
// 任务列表
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 () => { const init = async () => {
await getBelongPerList() await getBelongPerList()
getPlanList() // 任务列表需要当前归属人 id,所以保证上一步网络请求完成 getPlanList() // 任务列表需要当前归属人 id,所以保证上一步网络请求完成
...@@ -1256,50 +262,3 @@ const init = async () => { ...@@ -1256,50 +262,3 @@ const init = async () => {
}; };
init() init()
</script> </script>
\ No newline at end of file
<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
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论