feat: 增加转会商续报功能

This commit is contained in:
2025-12-17 21:20:41 +08:00
parent 45a1a1ea17
commit 7750f239ec
5 changed files with 480 additions and 22 deletions

View File

@ -0,0 +1,147 @@
<template>
<el-input :style="{ width: inputWidth }" class="mosty-select" readonly v-model="inputName" :disabled="props.disabled" clearable
@click="xgfClick" @clear="clear">
<!-- <template #append>
<el-button title="" class='cursor' :disabled="props.disabled" @click="xgfClick">选择</el-button>
</template> -->
</el-input>
<!-- 相关方 -->
<ChooseUser id="most-user" v-model="isShowDialog" :Single="props.Single" :deptId="props.deptId" :data="userData"
@choosedUsers="userChange"></ChooseUser>
</template>
<script setup>
import ChooseUser from "@/components/ChooseList/ChooseUser/index.vue";
import { ref, defineProps, defineEmits, onMounted, watch, defineExpose, computed } from 'vue'
const props = defineProps({
dataList: {
type: Array,
default: () => ([])
},
disabled: {
type: Boolean,
default: false
},
// relatedid: {
// type: String,
// default: ''
// },
/** 是否单选 默认多选 */
Single: {
type: Boolean,
default: true
},
ids: {
type: String,
default: ''
},
cName: {
type: String,
default: ''
},
stlyrylx: {
type: String,
default: '01'
},
/** 父级部门 (即只选该部门下的单位),
* 如果没有"deptId"会只能选当前登录人的部门,(但是:登录人是安全科可以选所有部门) */
deptId: {
type: String,
},
// xgflx: {
// type: String,
// default: '09,10,15'
// },
/** 输入框宽度 */
width: [String, Number]
})
const emit = defineEmits(['change', 'update:ids', 'update:cName', 'clear'])
const isShowDialog = ref(false)
const xgfMan = ref('')
const xgfRyId = ref('')
const inputName = ref('')
const inputWidth = computed(() => {
if (props.width) {
if (typeof props.width === 'string') {
if (props.width.includes('px')) return props.width
if (!isNaN(Number(props.width))) return props.width + 'px'
return props.width
} else if (typeof props.width === 'number') {
return `${props.width}px`
}
}
})
const userChange = (val) => {
val = Array.isArray(val) ? val : []
val = val.filter(item => {
return !!item
})
const cName = val.map(item => {
// if (item.mobile) {
// return item.userName + '' + item.mobile + ''
// } else {
// }
return item.userName
}).toString();
const ids = val.map(item => {
return item.id
}).toString();
emit('update:ids', ids || '')
emit('update:cName', cName || '')
emit('change', val || {})
}
const xgfClick = () => {
if (props.disabled) return
isShowDialog.value = true
}
const clear = () => {
// xgfMan.value = ''
// xgfRyId.value = ''
emit('update:ids', '')
emit('update:cName', '')
emit('change', {})
}
const closeDialog = (val) => {
isShowDialog.value = val
}
// 数组回显
const userData = computed(() => {
if (!props.ids || !props.ids.length) return []
if (props.Single) return props.ids
if (typeof props.ids === 'string') return props.ids.split(',')
return []
})
// input回显
watch(() => props.cName, (val) => {
inputName.value = val
}, { immediate: true })
onMounted(() => {
// console.log('2332===', props.xgflx);
});
defineExpose({
clear
});
</script>
<style scoped lang="scss">
.mosty-select {
width: 374px;
}
::v-deep .el-form {
margin-top: 0;
margin-bottom: 10px;
}
// ::v-deep #xgfandzzjgry .el-button + .el-button{
// margin-left: 10px;
// }</style>
::v-depp .treeBox {
margin-top: 10px;
}
<style></style>

View File

@ -381,3 +381,21 @@ export function holographicProfileJump(szhm) {
if (!szhm) return
window.open(`https://tyyy.lz.dsj.xz/profile/people/person-manage?sfzhm=${szhm}&from=portal`)
}
/**
* 获取表单验证错误信息
* @param fields 表单验证错误信息
* @param {Object} msgObj 错误信息Ojb,没有就取message
*/
export function getErrMsg(fields, msgObj) {
if (!fields) return;
if (Object.keys(fields).length === 0) return;
/** 第一个错误字段 */
const firstErrorField = Object.keys(fields)[0];
if (msgObj && msgObj[firstErrorField]) return msgObj[firstErrorField];
if (!firstErrorField) return;
/** 第一个错误字段的内容 @type{<Array>Object} - [message, field, fieldValue] */
let firstErrorFieldObj = fields?.[firstErrorField];
let errMsg = firstErrorFieldObj?.[0]?.message
return errMsg
}

View File

@ -109,7 +109,7 @@
<script setup>
import FormMessage from "@/components/aboutTable/FormMessage.vue";
import { xxcjAddEntity, xxcjUpdateEntity, xxcjSelectByid, xxcjSelectCzlcList, xxcjSelectListBc, xxcjDeletesBc } from "@/api/xxcj.js"
import { xxcjAddEntity, xxcjUpdateEntity, xxcjSelectByid, xxcjSelectCzlcList, xxcjSelectListBc, xxcjDeletesBc, addEntity, xxcjXxzhs } from "@/api/xxcj.js"
import { EditPen, Delete } from '@element-plus/icons-vue'
import { ref, defineExpose, onMounted, defineEmits, watch, getCurrentInstance } from "vue"
import { ElMessage } from 'element-plus';
@ -136,16 +136,24 @@ const formData = ref();
const rules = ref({
qbmc: [{ required: true, message: "请输入情报标题", trigger: "blur" }],
qbnr: [{ required: true, message: "请输入情报内容", trigger: "blur" }],
bcnr: [{ required: true, message: "请输入续报内容", trigger: "blur" }],
})
watch(() => dialogForm.value, (val) => {
if (val) {
if (formType.value === 'followUpReport') {
formData.value = [
{ label: "情报标题", prop: "qbmc", type: "input", width: '45%', disabled: true },
{ label: "续报内容", prop: "bcnr", type: "textarea", width: '100%', rows: 100 },
]
} else {
formData.value = [
{ label: "情报标题", prop: "qbmc", type: "input", width: '45%' },
{ label: "情报内容", prop: "qbnr", type: "textarea", width: '100%', rows: 100 },
{ label: "附件上传", prop: "fjdz", type: "upload", width: '100%', isImg: false },
]
}
}
}, { deep: true })
const fjdz = ref()
const listQuery = ref({}); //表单
@ -156,13 +164,22 @@ const msgeDat = ref()
const title = ref("")
const showPj = ref(false)
const disabled = ref(false)
/** 类型 add 新增 info 详情 edit 编辑 followUpReport 续报*/
const formType = ref('add')
// 初始化数据
const init = (type, row) => {
title.value = type == "add" ? "新增" : type == "info" ? "详情" : "编辑"
const titleObj = {
add: "新增",
info: "详情",
edit: "编辑",
followUpReport: "续报"
}
title.value = titleObj[type]
disabled.value = type == 'info' ? true : false
fjdz.value = []
dialogForm.value = true;
if (type == 'info' || type == 'edit') {
formType.value = type
if (type == 'info' || type == 'edit' || type == 'followUpReport') {
showPj.value = true
msgeDat.value = row
getqbcjPldb(row.id)
@ -178,7 +195,7 @@ const init = (type, row) => {
// 根据id查询详情
const getDataById = (id) => {
xxcjSelectByid({ id }).then((res) => {
console.log(res);
lcList.value = res.czlcList || []
listQuery.value = res;
listQuery.value.fjdz = res.fjdz ? res.fjdz?.split(",") : []
@ -188,9 +205,9 @@ const getDataById = (id) => {
// 新增
const submitForm = () => {
loading.value = true
elform.value.submit(valid => {
if (valid) {
loading.value = true
const promes = {
...listQuery.value,
fjdz: listQuery.value.fjdz && listQuery.value.fjdz.length > 0 ? listQuery.value.fjdz.map(item => {
@ -212,6 +229,19 @@ const submitForm = () => {
}).finally(() => {
loading.value = false
})
} else if (title.value == '续报') {
const params = {
qbid: listQuery.value.id,
czlx: '01',
ysnr: listQuery.value.qbnr,
bcnr: promes.bcnr,
}
addEntity(params).then((res) => {
emit("getList")
close()
}).finally(() => {
loading.value = false
})
}
}
})

View File

@ -0,0 +1,236 @@
<template>
<el-dialog v-model="dialogVisible" title="转会商" width="800px" :before-close="handleClose" destroy-on-close>
<el-form ref="formRef" :model="formData" :rules="rules" label-width="120px" label-position="right">
<!-- 会商标题 -->
<el-form-item label="会商标题" prop="hsbt">
<el-input v-model="formData.hsbt" placeholder="请输入会商标题" clearable />
</el-form-item>
<!-- 会商时间 -->
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="会商开始时间" prop="hskssj">
<el-date-picker v-model="formData.hskssj" type="datetime" placeholder="选择开始时间" format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss" style="width: 100%" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="会商结束时间" prop="hsjssj">
<el-date-picker v-model="formData.hsjssj" type="datetime" placeholder="选择结束时间" format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss" style="width: 100%" />
</el-form-item>
</el-col>
</el-row>
<!-- 参会人员 -->
<el-form-item label="参会人员" prop="chryList">
<inputUser v-model:ids="formData.chryList" v-model:cName="formData.chryListCname" :Single="false" width="250"
:multiple="true">
</inputUser>
</el-form-item>
<!-- 会商内容 -->
<el-form-item label="会商内容" prop="hsnr">
<el-input v-model="formData.hsnr" type="textarea" :rows="4" placeholder="请输入会商内容" maxlength="1000"
show-word-limit />
</el-form-item>
<!-- 会商处置意见 -->
<el-form-item label="会商处置意见" prop="czyj">
<el-input v-model="formData.czyj" type="textarea" :rows="3" placeholder="请输入会商处置意见" maxlength="500"
show-word-limit />
</el-form-item>
<!-- 评论内容 -->
<el-form-item label="评论内容" prop="plnr">
<el-input v-model="formData.plnr" type="textarea" :rows="3" placeholder="请输入评论内容" maxlength="500"
show-word-limit />
</el-form-item>
<!-- ID字段通常隐藏 -->
<el-form-item v-if="formData.id" label="ID" prop="id" style="display: none;">
<el-input v-model="formData.id" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="handleClose">取消</el-button>
<el-button type="primary" @click="handleSubmit" :loading="submitLoading">
确定
</el-button>
</div>
</template>
</el-dialog>
</template>
<script setup>
import { ref, reactive, onMounted, onBeforeUnmount } from 'vue'
import { xxcjXxzhs } from '@/api/xxcj.js'
import inputUser from '@/components/inputCom/inputUser.vue'
// Props
const props = defineProps({
title: {
type: String,
default: '转会商'
},
row: {
type: Object,
default: () => ({})
}
})
// Emits
const emit = defineEmits(['close', 'ok'])
// 响应式数据
const formRef = ref()
const submitLoading = ref(false)
/** 保存DTO对象 - 会商信息表单数据 */
const formData = ref({
/** 主键ID */
// id: '',
/** 会商标题 */
hsbt: '',
/** 关联线索ID(采集ID) */
glxsid: '',
/** 关联线索名称 */
glxsmc: '',
/** 会商开始时间 */
hskssj: '',
/** 会商结束时间 */
hsjssj: '',
/** 参会人员ID数组 */
chryList: [],
/** 会商内容 */
hsnr: '',
/** 会商处置意见 */
czyj: '',
/** 评论内容 */
plnr: ''
})
// 表单验证规则
const rules = reactive({
hsbt: [{ required: true, message: '会商标题不能为空', trigger: 'blur' }],
// glxsid: [
// { required: true, message: '请选择关联线索', trigger: 'change' }
// ],
hsnr: [{ required: true, message: '请输入会商内容', trigger: 'blur' },],
czyj: [
{ required: true, message: '会商处置意见不能为空', trigger: 'blur' }
],
plnr: [{ required: true, message: '评论内容不能为空', trigger: 'blur' },],
hskssj: [
{ required: true, message: '请选择会商开始时间', trigger: 'change' }
],
hsjssj: [
{ validator: validateEndTime, trigger: 'change' }
]
})
const dialogVisible = ref(false)
// 验证结束时间
function validateEndTime(rule, value, callback) {
if (value && formData.value.hskssj) {
const startTime = new Date(formData.value.hskssj)
const endTime = new Date(value)
if (endTime <= startTime) {
callback(new Error('结束时间必须大于开始时间'))
return
}
}
callback()
}
// 初始化表单数据
function initFormData() {
formData.value = {
hsbt: '',
glxsid: props.row.id,
glxsmc: props.row.qbmc,
// tsypid: '',
hskssj: '',
hsjssj: '',
chryList: '',
hsnr: '',
czyj: '',
plnr: ''
}
}
// 重置表单
function resetForm() {
if (formRef.value) {
formRef.value.resetFields()
}
initFormData()
}
function strToArr(str) {
if (!str) return []
if (typeof str === 'string') {
return str.split(',')
}
if (!Array.isArray(str)) return []
return str
}
// 提交表单
function handleSubmit() {
formRef.value.validate((valid) => {
if (valid) {
submitLoading.value = true
const chryList = strToArr(formData.value.chryList)
const params = { ...formData.value, chryList }
xxcjXxzhs(params).then(res => {
emit('close')
emit('ok')
}).finally(() => {
submitLoading.value = false
})
} else {
}
})
}
// 关闭对话框
function handleClose() {
emit('close')
}
onMounted(() => {
resetForm()
dialogVisible.value = true
})
onBeforeUnmount(() => {
dialogVisible.value = false
})
</script>
<style scoped>
.dialog-footer {
text-align: right;
}
.help-text {
font-size: 12px;
color: #909399;
margin-top: 4px;
}
:deep(.el-form-item__label) {
font-weight: 500;
}
:deep(.el-textarea__inner) {
resize: vertical;
}
</style>

View File

@ -92,7 +92,8 @@
<!-- 所有状态都能进行转合成 -->
<el-link v-if="isShowBtn('转合成')" size="small" type="primary" @click="openFkDialogszl(row)">转合成</el-link>
<!-- 所有状态都能进行转会商 -->
<el-link v-if="isShowBtn('转会商')" size="small" type="primary" @click="addEdit('info', row)">转会商</el-link>
<el-link v-if="isShowBtn('转会商')" size="small" type="primary"
@click="handleTransferMerchant(row)">转会商</el-link>
<!-- 只有领导有肯定 -->
<el-link v-if="isShowBtn('肯定')" size="small" type="primary" @click="affirm(row)">肯定</el-link>
<el-link v-if="isShowBtn('关注部门')" size="small" type="primary" @click="FollowUpOnDept(row)">关注部门</el-link>
@ -101,7 +102,9 @@
<el-link v-if="isShowBtn('删除')" size="small" type="danger" @click="delDictItem(row.id)">删除</el-link>
<el-link v-if="isShowBtn('修改')" size="small" type="primary" @click="addEdit('edit', row)">修改</el-link>
<el-link v-if="isShowBtn('修改', row)" size="small" type="primary" @click="addEdit('edit', row)">修改</el-link>
<el-link v-if="isShowBtn('续报', row)" size="small" type="primary"
@click="addEdit('followUpReport', row)">续报</el-link>
<el-link v-if="isShowBtn('详情')" size="small" type="primary" @click="addEdit('info', row)">详情</el-link>
</template>
@ -134,6 +137,10 @@
<Fszl v-model="fszlShow" path="/xxcj/sendFqzl" :itemData="dataList" />
<CustomTag v-model="customTagShow" :dataList="dataList" @getList="getList" :dict="{ D_XXCJ_BQLX }" />
<Configuration v-model="configurationShow" :dataList="dataList" @getList="getList" />
<!-- 转会商 -->
<transferMerchant v-if="isShowTransferMerchantTc" :row="currRow" ref="transferMerchantRef" title="转会商" @close="isShowTransferMerchantTc = false" @ok="getList" />
</template>
<script setup>
@ -153,6 +160,8 @@ import { getItem } from '@//utils/storage.js'
import Fszl from '@/views/backOfficeSystem/HumanIntelligence/components/fszl.vue'
import CustomTag from '../components/customTag.vue'
import Configuration from '../components/configuration.vue'
import transferMerchant from "./components/transferMerchant.vue";
const { proxy } = getCurrentInstance();
const { D_GS_XS_LY, D_BZ_SSZT, D_BZ_SF, D_GS_XS_LX, D_BZ_BQJB,
D_GS_XS_QTLX, D_GS_ZDQT_LB,
@ -172,6 +181,9 @@ const chooseData = (val) => {
tableList.value = val
}
const currRow = ref({})
const transferMerchantRef = ref()
const isShowTransferMerchantTc = ref(false)
const isShow = ref(false)
const searchConfiger = ref([
@ -538,7 +550,6 @@ const openFkDialogszl = (row) => {
/** 获取当前角色 */
function getRole() {
const { deptBizType, deptLevel } = getItem('deptId')[0]
// JS_666666 市情指领导 JS_777777 市情指人员 JS_888888 县情指人员
/** 是否是市情指领导 */
const isShiQzLeader = getItem('roleList').find(item => item.roleCode == 'JS_666666') != undefined
if (isShiQzLeader) return '市情指领导'
@ -551,18 +562,34 @@ function getRole() {
return '部门'
}
/** 是否展示按钮 */
const isShowBtn = (btnName) => {
const isShowBtn = (btnName, row = {}) => {
/** @type {String} 流程状态01 提交 02 上报县局 03 上班市局 04 采纳 05 退回 06 打标签 08 转线索) */
const lczt = row.lczt
/** 按钮权限 */
const buttonPermissions = {
"市情指领导": ["肯定", "采纳", "回退", "分组", "转线索", "转合成", "转会商", "修改", "详情"],
"市情指挥人员": ["采纳", "回退", "分组", "转线索", "转合成", "转会商", "修改", "详情"],
"县情指人员": ["上报", "回退", "修改", "详情"],
"部门": ["上报", "新增", "修改", "续报"]
"部门": ["上报", "新增", "修改", "续报", "详情"]
};
const role = getRole(); // 角色
return buttonPermissions[role]?.includes(btnName) || false;
const isHadAuth = buttonPermissions[role]?.includes(btnName) // 当前角色所有会显示的按钮
if (!isHadAuth) return false
// 拦截部分逻辑
if (role === '部门') {
if (btnName === '续报') return lczt != '01'
if (btnName === '修改') return lczt == '01'
// if(btnName === '上报') return lczt == '01'
}
return true
}
const handleTransferMerchant = (row) => {
currRow.value = row
isShowTransferMerchantTc.value = true
}
</script>