任务清单-->日常任务包列表处理 下发任务 修改任务处理

This commit is contained in:
maojiacai
2025-09-07 20:35:37 +08:00
parent f2faa2d5fd
commit 042c48fa96
10 changed files with 2163 additions and 15952 deletions

View File

@ -1,5 +0,0 @@
const express = require('express')
const app = express()
app.get('/', (req, res) => res.send('Hello World!'))
app.use(express.static('./www'))
app.listen(3000, () => console.log('Example app listening on port 3000!'))

15939
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,30 @@
// 指导巡逻-方格巡逻任务接口
import request from "@/utils/request";
const api = "/mosty-api/mosty-yjzl";
// 分页查询
export function getSelectPage(params) {
return request({
url: api + '/tbZdxlFgxlrw/selectPage',
method: 'GET',
params
})
}
// 修改数据
export function updateData(data) {
return request({
url: api + '/tbZdxlFgxlrw/update',
method: 'POST',
data
})
}
// 下发
export function fetchIssueData(data) {
return request({
url: api + '/tbZdxlFgxlrw/issueList',
method: 'POST',
data
})
}

View File

@ -311,3 +311,15 @@
width: 100%; width: 100%;
} }
::v-deep .el-descriptions {
--el-border-color-lighter: #0a467e;
.is-bordered-content, .is-bordered-label {
color: #ffffff;
}
.is-bordered-label {
background-color: #335f883b !important;
}
}

View File

@ -24,6 +24,7 @@
<el-table-column <el-table-column
type="selection" type="selection"
width="55" width="55"
:selectable="selectable"
v-if="getConfiger.showSelectType === 'checkBox'" v-if="getConfiger.showSelectType === 'checkBox'"
/> />
<el-table-column <el-table-column
@ -116,6 +117,10 @@ const props = defineProps({
fixed: { fixed: {
type: String, type: String,
default: "right" default: "right"
},
selectable: {
type: Function,
default: () => {}
} }
}); });
// 可选的时候选择的数据 // 可选的时候选择的数据

View File

@ -23,7 +23,7 @@
</template> </template>
<script setup> <script setup>
import axios from "axios"; import request from "@/utils/request";
import { ElMessage } from "element-plus"; import { ElMessage } from "element-plus";
import { qcckPost, qcckGet } from "@/api/qcckApi.js"; import { qcckPost, qcckGet } from "@/api/qcckApi.js";
import { useStore } from "vuex"; import { useStore } from "vuex";
@ -62,6 +62,10 @@ watch(() => props.lx, (val) => {
baseUrl.value = '/mosty-api/mosty-jcgl/tpjcglZnzb/importData' baseUrl.value = '/mosty-api/mosty-jcgl/tpjcglZnzb/importData'
modelUrl.value = '/mosty-api/mosty-jcgl/tpjcglZnzb/importTemplate' modelUrl.value = '/mosty-api/mosty-jcgl/tpjcglZnzb/importTemplate'
break; break;
case 'rcrwb':
baseUrl.value = '/mosty-api/mosty-yjzl/tbZdxlFgxlrw/importListByMb'
// modelUrl.value = '/mosty-api/mosty-jcgl/tpjcglZnzb/importTemplate'
break;
default: default:
break; break;
} }
@ -100,6 +104,14 @@ function downloadModel() {
window.open(modelUrl.value, "_self"); window.open(modelUrl.value, "_self");
} }
const upload = (data) => {
return request({
url: baseUrl.value,
method: "POST",
headers: { "Content-type": "multipart/form-data" },
data: data,
})
}
// 确定上传 // 确定上传
function onComfirm() { function onComfirm() {
if (filesList.value.length <= 0) { if (filesList.value.length <= 0) {
@ -109,10 +121,18 @@ function onComfirm() {
let formData = new FormData(); let formData = new FormData();
formData.append("file", file); formData.append("file", file);
formData.append("updateSupport", isSelect.value); formData.append("updateSupport", isSelect.value);
axios.post(baseUrl.value, formData, { "Content-type": "multipart/form-data" }) upload(formData)
.then((res) => { .then((res) => {
if (res.status == 200) { if (res.status == 200 || res) {
let { data, message, code } = res.data; if (!res?.data) {
if (!res) ElMessage({ type: 'warning', message: message, dangerouslyUseHTMLString: true });
if (res) ElMessage({ type: 'success', message: '导入成功', dangerouslyUseHTMLString: true });
emits("handleImport");
handleClose();
return
}
let { data, message, code } = res?.data;
if (code == -1) ElMessage({ type: 'warning', message: message, dangerouslyUseHTMLString: true }); if (code == -1) ElMessage({ type: 'warning', message: message, dangerouslyUseHTMLString: true });
if (code == 10000) ElMessage({ type: 'success', message: data, dangerouslyUseHTMLString: true }); if (code == 10000) ElMessage({ type: 'success', message: data, dangerouslyUseHTMLString: true });
emits("handleImport"); emits("handleImport");

View File

@ -558,6 +558,26 @@ export const privateRoutes = [{
icon: "article-ranking" icon: "article-ranking"
} }
}, },
{
path: "/service/taskPage",
component: () => import("@/views/backOfficeSystem/service/taskPage/dailyTaskPackage/index"),
name: "taskPage",
meta: {
title: '任务清单',
icon: "article-ranking"
},
children: [
{
path: "/taskPageIndex",
component: () => import("@/views/backOfficeSystem/service/taskPage/dailyTaskPackage/index"),
name: "taskPageIndex",
meta: {
title: '日常任务包',
icon: "article-ranking"
},
}
]
},
{ {
path: "/service/statutoryHolidays", path: "/service/statutoryHolidays",
component: () => import("@/views/backOfficeSystem/service/statutoryHolidays/index"), component: () => import("@/views/backOfficeSystem/service/statutoryHolidays/index"),

View File

@ -0,0 +1,270 @@
<template>
<div>
<div v-if="dialogFormVisible" class="dialog">
<div class="head_box">
<span class="title">{{ title }}</span>
<div>
<el-button
v-if="!infoActive"
type="primary"
size="small"
@click="submit"
:loading="btnLoading"
>保存</el-button
>
<el-button size="small" @click="close">关闭</el-button>
</div>
</div>
<div class="dialogWrapper">
<div class="label">任务包基本信息</div>
<el-descriptions
class="margin-top"
:column="3"
border
>
<!-- <template #extra>-->
<!-- <el-button type="primary">Operation</el-button>-->
<!-- </template>-->
<el-descriptions-item label="方格名称">
{{ form?.fgMc }}
</el-descriptions-item>
<el-descriptions-item label="预警等级">
<dict-tag :options="D_ZDXL_FGXLRW_YJDJ" :value="form?.fgYjdj" :tag="false" />
</el-descriptions-item>
<el-descriptions-item label="警情数量">
{{ form?.fgYjjqsl }}
</el-descriptions-item>
<el-descriptions-item label="高发时段">
{{ form?.fgYjgfsd }}
</el-descriptions-item>
<el-descriptions-item label="高发类型">
{{ form?.fgJqtjLx }}
</el-descriptions-item>
<el-descriptions-item label="任务日期">
{{ form?.rwRq }}
</el-descriptions-item>
<el-descriptions-item label="小时统计">
{{ form?.fgJqtjXsLabel }}
</el-descriptions-item>
</el-descriptions>
<div class="label" style="margin-top: 1rem">任务包下发编辑信息</div>
<el-form
ref="formRef"
:model="form"
:rules="rules"
:inline="true"
:disabled="infoActive"
>
<el-form-item prop="xlghSc" label="巡逻时长:">
<el-input-number
style="width: 80%;"
min="0"
placeholder="请填写巡逻时长"
v-model="form.xlghSc"
></el-input-number>
<el-tag size="small" type="warning">分钟</el-tag>
</el-form-item>
<el-form-item prop="xlghPcRy" label="盘查人员:">
<el-input
placeholder="请填写盘查人员"
clearable
v-model="form.xlghPcRy"
></el-input>
</el-form-item>
<el-form-item prop="xlghPcCl" label="盘查车辆:">
<el-input
placeholder="请填写盘查车辆"
clearable
v-model="form.xlghPcCl"
></el-input>
</el-form-item>
<el-form-item prop="xlghXllc" label="巡逻里程:">
<el-input-number
style="width: 80%;"
min="0"
placeholder="请填写巡逻里程"
v-model="form.xlghXllc"
></el-input-number>
<el-tag size="small" type="warning">公里</el-tag>
</el-form-item>
<el-form-item prop="xfbbName" label="下发巡组:">
<el-input
placeholder="请填写下发巡组"
clearable
v-model="form.xfbbName"
@click="visible = true"
readonly
></el-input>
</el-form-item>
<template v-for="(item, index) in form?.bddList" :key="index">
<el-form-item :prop="`bddList[${index}].xlghDkcs`" :label="`打卡点${index + 1}:`" :rules="checkPointRules">
<el-input-number
style="width: 100%;"
:placeholder="`输入打卡点${index + 1}需打卡次数`"
clearable
v-model="item.xlghDkcs"
/>
</el-form-item>
</template>
</el-form>
</div>
</div>
<distribute-patrol-team-dialog v-model="visible" @selection-change="handleChange" />
</div>
</template>
<script setup>
import { ref, reactive, getCurrentInstance, computed } from "vue";
import { updateData } from "@/api/service/dailyTaskPackage";
import DictTag from "@/components/DictTag/index.vue";
import DistributePatrolTeamDialog
from "@/views/backOfficeSystem/service/taskPage/dailyTaskPackage/components/DistributePatrolTeamDialog.vue";
const { proxy } = getCurrentInstance();
const { D_ZDXL_FGXLRW_YJDJ } = proxy.$dict("D_ZDXL_FGXLRW_YJDJ");
const btnLoading = ref(false); //按钮截流
const title = ref("修改");
const formRef = ref(null);
const infoActive = ref(true);
const visible = ref(false);
//级联选择器配置
const props = defineProps({
modelValue: {
type: Boolean,
default: false
}
});
const emits = defineEmits(['update:modelValue', 'ok']);
const dialogFormVisible = computed({
get() {
return props.modelValue;
},
set(val) {
emits("update:modelValue", val);
}
})
//表单数据
const form = ref({
bddList: []
});
// 打卡点验证规则
const checkPointRules = [
{ required: true, message: '请输入打卡次数', trigger: 'change' },
{
validator: (rule, value, callback) => {
if (value < 1) {
callback(new Error('打卡次数必须大于0'));
} else {
callback();
}
},
trigger: 'change'
}
];
//表单验证
const rules = reactive({
xlghXllc: [
{
required: true,
message: "请填写巡逻里程",
trigger: "change"
}
],
xlghSc: [
{
required: true,
message: "请填写巡逻时长",
trigger: "change"
}
],
xlghPcRy: [
{
required: true,
message: "请填写盘查人员",
trigger: "change"
}
],
xlghPcCl: [
{
required: true,
message: "请填写盘查车辆",
trigger: "change"
}
],
xfbbName: [
{
required: true,
message: "请填写下发巡组",
trigger: "change"
}
],
});
//新增
function open(row = {}, type) {
infoActive.value = type === 'view';
form.value = { ...row, xfbbName: row?.xfxz };
title.value = "编辑信息";
dialogFormVisible.value = true;
}
//关闭弹窗
function close() {
formRef.value.resetFields();
dialogFormVisible.value = false;
}
const handleChange = (val) => {
form.value.xfbbId = val?.[0]?.id;
form.value.xfbbName = `${val?.[0]?.fzrXm}警组`;
}
//提交
const submit = async () => {
try {
await formRef.value.validate()
await updateData(form.value)
proxy.$message({
type: "success",
message: "修改成功"
});
dialogFormVisible.value = false;
emits("ok")
} catch (error) {
console.log(error);
}
}
defineExpose({ open })
</script>
<style lang="scss" scoped>
@import "~@/assets/css/layout.scss";
@import "~@/assets/css/element-plus.scss";
.dialog {
.dialogWrapper {
margin: 20px 20px 0 20px;
.el-form--inline {
padding: 0 0 0rem 0;
}
}
}
.label {
margin-bottom: 1rem;
}
</style>

View File

@ -0,0 +1,368 @@
<script setup>
import { computed, getCurrentInstance, onMounted, reactive, ref } from "vue";
const { proxy } = getCurrentInstance();
const { D_BZ_XB, D_ZDXL_FGXLRW_YJDJ, D_ZDXL_FGXLRW_RWZT } = proxy.$dict("D_BZ_XB", "D_ZDXL_FGXLRW_YJDJ", "D_ZDXL_FGXLRW_RWZT");
import PageTitle from "@/components/aboutTable/PageTitle.vue";
import Search from "@/components/aboutTable/Search.vue";
import MyTable from "@/components/aboutTable/MyTable.vue";
import Pages from "@/components/aboutTable/Pages.vue";
import EditAddFormDialog from "@/views/backOfficeSystem/service/taskPage/dailyTaskPackage/editAddFormDialog.vue";
import Export from "@/components/export/index.vue";
import { fetchIssueData, getSelectPage } from "@/api/service/dailyTaskPackage";
const searchConfiger = reactive([
{
showType: "input",
prop: "fgMc",
placeholder: "请输入方格名称",
label: "方格名称"
},{
showType: "select",
prop: "fgYjdj",
placeholder: "请选择预警等级",
label: "预警等级:",
options: D_ZDXL_FGXLRW_YJDJ
},
{
showType: "date",
prop: "rwRq",
placeholder: "请选择任务日期",
label: "任务日期:",
},
])
const searchBox = ref() //搜索框
const deleteIds = ref([]) // 删除id
const isImport = ref(false);
const dialogFormVisible = ref(false);
const pageData = reactive({
visible: true,
tableData: [], //表格数据
keyCount: 0,
tableConfiger: {
rowHieght: 61,
showSelectType:'checkBox',
loading:false
},
total: 0,
pageConfiger: {
pageSize: 10,
pageCurrent: 1
}, //分页
controlsWidth: 210, //操作栏宽度
tableColumn: [
{
label: "方格名称 ",
prop: "fgMc"
},
{
label: "预警等级",
prop: "fgYjdj",
showSolt:true
},
{
label: "警情数量",
prop: "fgYjjqsl"
},
{
label: "高发时段",
prop: "fgYjgfsd",
},
{
label: "高发类型",
prop: "fgJqtjLx",
showOverflowTooltip: true,
},
{
label: "任务日期",
prop: "rwRq",
},
{
label: "巡逻时长",
prop: "xlghSc",
showSolt:true
},
{
label: "盘查人员",
prop: "xlghPcRy",
},
{
label: "盘查车辆",
prop: "xlghPcCl",
},
{
label: "巡逻里程",
prop: "xlghXllc",
showSolt:true
},
{
label: "下发巡组",
prop: "xfxz",
},
{
label: "每个打卡点",
prop: "bddListLabel",
showOverflowTooltip: true,
},
{
label: "下发状态",
prop: "rwZt",
showSolt:true
},
]
})
const selectable = (row) => row?.rwZt === '01' || row?.rwZt === '02'
const editAddFormRef = ref(null);
const addEdit = (row, type) => {
editAddFormRef.value?.open(row, type)
}
const handleIssueAll = () => {
if (deleteIds.value.length === 0) {
proxy.$message({
message: "请选择勾选要下发的任务",
type: "warning"
});
return
}
handleIssue(deleteIds.value)
}
// 下发
const handleIssue = async (ids = []) => {
try {
await proxy.$confirm("是否进行下发操作", "警告", {type: "warning"})
const res = await fetchIssueData({ ids: ids?.join(',') })
if (res) {
proxy.$message({type: "success", message: "下发成功" });
handleFilter()
deleteIds.value = []
}
} catch (error) {
console.log(error);
}
}
// 删除
const delDictItem = (id) => {
batchDelete(id)
}
const chooseData = (val) => {
if (val?.length > 0) {
deleteIds.value = val?.map((item) => item.id);
} else {
deleteIds.value = []
}
}
const onSearch = (val) => {
const { cz, ...ret } = val
pageData.pageConfiger.pageCurrent = 1;
getListData(ret);
}
// 表格高度计算
const tabHeightFn = () => {
pageData.tableHeight = window.innerHeight - searchBox.value.offsetHeight - 244;
window.onresize = function () { tabHeightFn(); };
};
const parseAndJoinLx = (jsonString, type = 'lx') => {
if (!jsonString) return '';
try {
let data = jsonString;
// 如果是字符串尝试解析为JSON
if (typeof jsonString === 'string') {
data = JSON.parse(jsonString);
}
// 处理数组情况
if (Array.isArray(data)) {
return data.map(item => item?.[type]).filter(Boolean).join(",");
}
// 处理对象情况
if (typeof data === 'object' && data !== null) {
return data?.[type] || '';
}
return '';
} catch (error) {
console.warn('数据处理失败:', error);
return '';
}
};
const getListData = async (params = {}) => {
pageData.tableConfiger.loading = true
try {
const res = await getSelectPage({
...pageData.pageConfiger,
...params
})
pageData.tableData = res?.records?.map((item) => ({
...item,
xfxz: item?.xfbb?.fzrXm ? `${item?.xfbb?.fzrXm}警组` : '-',
bddListLabel: item?.bddList?.map((i, idx) => (`卡点${idx + 1}-${i?.xlghDkcs}`))?.join(',') || '-',
fgJqtjXsLabel: JSON.parse(item?.fgJqtjXs)?.filter(i => (i?.count !== 0))?.map(i => (`${i?.hour}小时-${i?.count}`))?.join('、') || '-',
fgJqtjLx: parseAndJoinLx(item?.fgJqtjLx, 'lx')
})) || []
// pageData.tableData[0].rwZt = '03'
console.log(pageData.tableData);
pageData.total = res.total;
pageData.tableConfiger.loading = false;
} catch (err) {
pageData.tableConfiger.loading = false;
}
}
const changeNo = (val) => {
pageData.pageConfiger.pageCurrent = val;
getListData();
}
const changeSize = (val) => {
pageData.pageConfiger.pageSize = val;
getListData();
}
const handleFilter = () => {
pageData.pageConfiger.pageCurrent = 1;
getListData();
}
// 删除的方法
//批量删除数据
const batchDelete = async (id) => {
await proxy.$confirm("确定要删除", "警告", { type: "warning" })
try {
// await zbPbDelete(id)
proxy.$message({
message: "删除成功",
type: "success"
});
getListData();
} catch (error) {
console.log(error);
}
};
// 批量删除
const handleDel = () => {
if (deleteIds.value.length === 0) {
proxy.$message({
message: "请选择勾选要删除的数据",
type: "warning"
});
return
}
batchDelete(deleteIds)
}
onMounted(() => {
proxy.mittBus.on("mittFn", (data) => { pageData.keyCount = data; });
tabHeightFn()
getListData()
})
</script>
<template>
<div class="container">
<div class="titleBox">
<PageTitle title="日常任务包">
<el-button typeof="danger" :disabled="deleteIds.length === 0" @click="handleIssueAll">
<span style="vertical-align: middle">批量下发</span>
</el-button>
<el-button type="primary" @click="isImport = true">
<span style="vertical-align: middle">导入</span>
</el-button>
<!-- <el-button typeof="danger" :disabled="deleteIds.length === 0" @click="handleDel">-->
<!-- <el-icon style="vertical-align: middle"><Delete /> </el-icon>-->
<!-- <span style="vertical-align: middle">批量删除</span>-->
<!-- </el-button>-->
<!-- </PageTitle>-->
</div>
<div ref="searchBox">
<Search :searchArr="searchConfiger" @submit="onSearch" />
</div>
<div class="tabBox">
<MyTable
:tableData="pageData.tableData"
:tableColumn="pageData.tableColumn"
:tableHeight="pageData.tableHeight"
:key="pageData.keyCount"
:tableConfiger="pageData.tableConfiger"
:controlsWidth="pageData.controlsWidth"
:selectable="selectable"
@chooseData="chooseData"
>
<template #fgYjdj="{ row }">
<dict-tag :options="D_ZDXL_FGXLRW_YJDJ" :value="row.fgYjdj" :tag="false" />
</template>
<template #rwZt="{ row }">
<dict-tag :options="D_ZDXL_FGXLRW_RWZT" :value="row.rwZt" :tag="false" />
</template>
<template #xlghXllc="{ row }">
<div>{{ `${row.xlghXllc}公里` }}</div>
</template>
<template #xlghSc="{ row }">
<div>{{ `${row.xlghSc}分钟` }}</div>
</template>
<!-- 操作 -->
<template #controls="{ row }">
<el-button size="small" @click="addEdit(row, 'del')">编辑</el-button>
<el-button size="small" @click="addEdit(row, 'view')">查看详情</el-button>
<el-button size="small" v-if="row?.rwZt === '01' || row?.rwZt === '02'" @click="handleIssue([row.id])">下发</el-button>
<!-- <el-button size="small" @click="delDictItem([row.id])">删除</el-button>-->
</template>
</MyTable>
<Pages
@changeNo="changeNo"
@changeSize="changeSize"
:tableHeight="pageData.tableHeight"
:pageConfiger="{
...pageData.pageConfiger,
total: pageData.total
}"
/>
</div>
<edit-add-form-dialog ref="editAddFormRef" v-model="dialogFormVisible" @ok="handleFilter" />
<Export
:show="isImport"
lx="rcrwb"
@closeImport="isImport = !isImport"
@handleImport="handleFilter"
/>
</div>
</template>
<style scoped lang="scss">
.container {
::v-deep {
.check, .el-upload-text {
display: none;
}
.el-descriptions__body {
background-color: transparent !important;
color: #fff;
}
}
}
</style>