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

feat(mobile/promotion/plan): 促销移动端:批量删除计划功能

同上
上级 53641a5e
......@@ -19,8 +19,8 @@ const { x, y } = useWindowScroll({
lang="scss">
.back-to-top {
position: fixed;
bottom: 30px;
right: 10px;
bottom: 50px;
right: 24px;
z-index: 999;
width: 46px;
height: 46px;
......
// 长按手势指令
import { ref } from 'vue';
const longPressDuration = ref(500); // 长按时间阈值,单位毫秒
let start = null; // 记录触摸开始时间
let cancel = null;
export default {
beforeMount(el, binding) {
let pressTimer = null;
start = (e) => {
if (pressTimer === null) {
pressTimer = setTimeout(() => {
binding.value();
}, longPressDuration.value);
}
};
cancel = (e) => {
if (pressTimer !== null) {
clearTimeout(pressTimer);
pressTimer = null;
}
};
el.addEventListener('touchstart', start);
el.addEventListener('touchend', cancel);
el.addEventListener('touchcancel', cancel);
},
unmounted(el) {
el.removeEventListener('touchstart', start);
el.removeEventListener('touchend', cancel);
el.removeEventListener('touchcancel', cancel);
}
};
\ No newline at end of file
......@@ -5,6 +5,9 @@ import PickerSearch from './components/PickerSearch'
// 选择日期
import PickerCalendar from './components/PickerCalendar'
// 指令
import longPress from './directive/touch'
// 只有在移动端引入
if (isMobile()) {
(function () {
......@@ -25,4 +28,5 @@ if (isMobile()) {
export default function (app) {
app.component('PickerSearch', PickerSearch);
app.component('PickerCalendar', PickerCalendar);
app.directive('longPress', longPress)
}
<template>
<div class="mobile-container">
<div v-for="(module, moduleIndex) in modules"
:key="moduleIndex"
class="function-module">
<p class="function-module-title">{{ module.title }}</p>
<div class="function-icons">
<div v-for="(icon, iconIndex) in module.icons"
:key="iconIndex"
class="function-icon"
@click="handleIconClick(icon)">
<div class="function-icon-wrap"
:style="{ backgroundColor: icon.iconColor }">
<van-icon :name="icon.iconName" />
</div>
<p>{{ icon.name }}</p>
</div>
</div>
</div>
</div>
</template>
<script setup>
const router = useRouter();
const modules = [
{
title: '促销管理',
icons: [
{ name: '促销计划', iconName: 'shop-o', iconColor: '#5aaeec', to: '/m/promotion_plan' },
{ name: '稽核', iconName: 'manager-o', iconColor: '#feb73b', to: '/m/promotion_plan' },
]
}
]
const handleIconClick = (icon) => {
router.push(icon.to)
};
</script>
<style scoped
lang="scss">
.mobile-container {
background-color: #f3f3f3;
min-height: 100%;
font-size: 14px;
padding: 20px;
p {
margin: 0;
}
.function-module {
background-color: #fff;
/* 设置白色背景 */
border-radius: 8px;
/* 设置圆角 */
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
/* 添加阴影 */
padding: 16px;
/* 添加内边距 */
margin-bottom: 16px;
/* 设置模块间的间距 */
.function-module-title {
font-size: 16px;
/* 设置标题字体大小 */
font-weight: bold;
/* 设置标题字体加粗 */
margin-bottom: 16px;
/* 设置标题与内容的间距 */
}
.function-icons {
display: flex;
flex-wrap: wrap;
gap: 16px;
/* 设置图标间的间距 */
.function-icon {
width: 80px;
text-align: center;
.function-icon-wrap {
width: 60px;
height: 60px;
margin: 0 auto 10px;
background-color: aqua;
display: flex;
justify-content: center;
align-items: center;
border-radius: 50%;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
.van-icon {
color: white;
font-size: 35px;
}
}
}
}
}
}
</style>
\ No newline at end of file
......@@ -363,6 +363,10 @@ const onChange = (ind) => {
height: 135px;
}
p {
display: block;
}
}
&::-webkit-scrollbar-track {
......
......@@ -162,8 +162,12 @@
import { getPlanStoreListAPI, getChargeListAPI, addPlanByWebAPI, getPlanDetailAPI, updatePlanByWebAPI } from '@/api'
import userStore from '@/store/modules/user'
import { parseTime } from '@/utils'
const myForm = ref({})
const { proxy } = getCurrentInstance();
const employeeNo = computed(() => userStore().employeeNo)
const employeeName = computed(() => userStore().employeeName)
const employeeInfo = computed(() => userStore().employeeInfo)
const isCityManager = ref(userStore().promotionIdentity)
const form = reactive({})
const router = useRouter();
......@@ -208,10 +212,10 @@ const validatorIncidentals = (value, obj) => {
}
}
const onSubmit = async () => {
const data = userStore().employeeInfo
for (const key in data) {
form[key] = data[key]
for (let key in employeeInfo.value) {
form[key] = employeeInfo.value[key]
}
if (planId) {
const res = await updatePlanByWebAPI(form)
proxy.$modal.msgSuccess(res.msg)
......@@ -219,6 +223,7 @@ const onSubmit = async () => {
const res = await addPlanByWebAPI(form)
proxy.$modal.msgSuccess(res.msg)
}
clickBack()
}
......@@ -278,7 +283,8 @@ const getBelongList = async () => {
const res = await getChargeListAPI()
allBelongList.value = res.data.map(item => ({
text: item.name,
value: item.employeeNo
value: item.employeeNo,
id: item.id
}))
columns.value = allBelongList.value
// 判断如果是城市经理,则设置默认归属人为自己
......@@ -370,6 +376,7 @@ const confirm = (value) => {
const { selectedOptions } = value
form.employeeName = selectedOptions[0]?.text
form.employeeNo = selectedOptions[0]?.value
form.employeeId = selectedOptions[0]?.id
}
showPicker.value = false
}
......
<template>
<div class="mobile-container">
<van-nav-bar right-text="搜索"
left-text="新增计划"
@click-left="$router.push('/m/promotion_plan_editing')"
left-arrow
@click-left="$router.back()"
@click-right="showSearch = true"
placeholder
fixed />
......@@ -18,9 +18,13 @@
@load="onLoad">
<van-cell-group inset>
<van-swipe-cell v-for="item in planList"
:key="item.id">
:key="item.id"
v-long-press="onLongPress">
<van-checkbox v-show="showSelect"
v-model="item.checked"
shape="square" />
<van-cell :title="item.storeName"
:to="`/m/promotion_plan_detail/${item.id}`">
@click="clickDetail(item)">
<template #label>
<p class="employee">{{ item.employeeName }}</p>
<p :class="{ 'plan-go': item.planStatus === 1 }">
......@@ -32,7 +36,8 @@
<p>{{ parseTime(item.date, '{y}-{m}-{d} (周{a})') }}</p>
</template>
</van-cell>
<template #right>
<template #right
v-if="!showSelect">
<van-button square
type="success"
text="编辑"
......@@ -46,13 +51,24 @@
</van-cell-group>
</van-list>
</van-pull-refresh>
<!-- 搜索组件 -->
<PlanSearch v-model:show="showSearch"
v-model:query="query"
:planColumns="planColumns"
:allEmpolyeeList="allEmpolyeeList"
@query="querySearch" />
<!-- 新增组件(浮动气泡) -->
<van-floating-bubble icon="plus"
@click="$router.push('/m/promotion_plan_editing')" />
<!-- 底部-长按操作栏 -->
<van-action-bar v-show="showSelect">
<span @click="showSelect = false">取消</span>
<van-action-bar-button type="warning"
text="修改归属人" />
<van-action-bar-button type="danger"
text="删除"
@click="clickDelSome" />
</van-action-bar>
</div>
</template>
......@@ -150,15 +166,19 @@ const onRefresh = () => {
}, 300)
}
const clickDetail = (row) => {
if (showSelect.value) return // 当前处于长按状态,点击详情不做任何操作
router.push(`/m/promotion_plan_detail/${row.id}`)
}
// 搜索表单
const querySearch = () => {
query.pageNum = 1
planList.value = []
getPlanList()
onRefresh()
}
// 编辑计划
const editPlan = (row) => {
console.log(123)
if (!checkPlanExpire(row)) {
return proxy.$modal.msgWarning('无法编辑,已执行或之前计划')
}
......@@ -176,9 +196,8 @@ const deletePlan = (row) => {
employeeNo: employeeNo.value
})
proxy.$modal.msgSuccess('删除成功')
// 找到 row 在数组里第几条删除
const index = planList.value.findIndex(item => item.id === row.id)
planList.value.splice(index, 1)
// 重新获取列表
onRefresh()
})
}
......@@ -187,6 +206,40 @@ const init = async () => {
getPlanList()
}
init()
onActivated(() => {
querySearch()
})
// 长按出现全选功能
const showSelect = ref(false)
const onLongPress = () => {
showSelect.value = true
}
// 删除全选的计划
const clickDelSome = () => {
const ids = planList.value.filter(item => item.checked).map(item => item.id)
if (ids.length === 0) {
return proxy.$modal.msgWarning('请选择要删除的计划')
}
proxy.$modal.confirm(`确认删除${ids.length}条计划吗?`).then(async () => {
// 循环判断计划是否含有以前和执行中的
for (let i = 0; i < ids.length; i++) {
const item = planList.value.find(o => o.id === ids[i])
if (!checkPlanExpire(item)) {
return proxy.$modal.msgWarning('无法删除,已执行或之前计划')
}
}
await deletePlanAPI({
planIds: ids,
employeeNo: employeeNo.value
})
proxy.$modal.msgSuccess('删除成功')
showSelect.value = false
onRefresh()
})
}
</script>
<style scoped
......@@ -201,33 +254,60 @@ init()
.van-cell-group {
background: #f5f5f5;
.van-cell {
margin-top: 10px;
.van-swipe-cell {
/* 阻止长按选文字效果 */
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
.van-cell__label {
font-size: 14px !important;
}
/* Standard syntax */
::v-deep(.van-swipe-cell__wrapper) {
display: flex;
margin-top: 10px;
.employee {
margin-bottom: 5px !important;
}
.van-checkbox {
padding-right: 10px;
}
.plan-go {
color: #39bb74;
}
.van-cell {
p {
margin: 0;
}
}
.van-cell__label {
font-size: 14px !important;
}
.employee {
margin-bottom: 5px !important;
}
.van-swipe-cell__right {
display: flex;
.plan-go {
color: #39bb74;
}
button {
height: 100%;
p {
margin: 0;
}
}
.van-swipe-cell__right {
display: flex;
button {
height: 100%;
}
}
}
}
}
}
/* 底部菜单 */
.van-action-bar {
span {
font-size: 14px;
padding: 0 10px;
}
}
}
......
......@@ -95,10 +95,16 @@ export const constantMobileRoutes = [
},
{
path: '/m',
redirect: '/m/promotion_plan',
redirect: '/m/menu',
component: () => import('@/mobile/index'),
hidden: true,
children: [
// 菜单页
{
path: 'menu',
component: () => import('@/mobile/views/menu'),
name:'m_menu',
},
// 促销计划
{
path: 'promotion_plan', // 列表
......
......@@ -98,7 +98,7 @@ export default defineStore(
promotionIdentity(state) {
return getPromotionRole(state.userInfo.privilegeId) === CITY_MANAGER
},
// 获取员工工号,姓名,id
// 操作人员工工号,姓名,id
employeeInfo(state) {
return {
operNo: state.userInfo.userName,
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论