增加行政执法管理等部分前端页面
This commit is contained in:
parent
68f9b6d965
commit
27ff842418
|
|
@ -0,0 +1,594 @@
|
||||||
|
<template>
|
||||||
|
<browser
|
||||||
|
:component-loading="componentLoading"
|
||||||
|
:api-config="apiConfig"
|
||||||
|
:table-config="tableConfig"
|
||||||
|
:permissions="permissions"
|
||||||
|
:dialog-config="dialogConfig"
|
||||||
|
:actions="actions"
|
||||||
|
:default-query-params="queryParams"
|
||||||
|
@update:query-params="queryParams = $event"
|
||||||
|
@update:actions="actions = $event"
|
||||||
|
@update:dialog-config="dialogConfig = $event"
|
||||||
|
>
|
||||||
|
<!-- 查询面板 -->
|
||||||
|
<template #queryPanel="{ queryParams: qp }">
|
||||||
|
<el-form ref="queryForm" :model="qp" label-width="100px">
|
||||||
|
<el-row class="query-condition">
|
||||||
|
<el-col :span="6">
|
||||||
|
<el-form-item label="机构名称" prop="agencyName">
|
||||||
|
<el-input v-model="qp.agencyName" placeholder="请输入机构名称" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="6">
|
||||||
|
<el-form-item label="机构代码" prop="agencyCode">
|
||||||
|
<el-input v-model="qp.agencyCode" placeholder="请输入机构代码" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 自定义内容区域:左侧树形结构 + 右侧列表 -->
|
||||||
|
<template #table="{ permissions: perms, data, selection, mergeActions, queryParams: qp }">
|
||||||
|
<div class="agency-content">
|
||||||
|
<!-- 左侧树形结构 -->
|
||||||
|
<div class="agency-tree">
|
||||||
|
<div class="tree-header">
|
||||||
|
<span class="tree-title">机构树</span>
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
size="small"
|
||||||
|
@click="refreshTree"
|
||||||
|
:icon="Refresh"
|
||||||
|
circle
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<el-tree
|
||||||
|
ref="treeRef"
|
||||||
|
v-loading="treeLoading"
|
||||||
|
:data="treeData"
|
||||||
|
:props="treeProps"
|
||||||
|
:highlight-current="true"
|
||||||
|
:expand-on-click-node="false"
|
||||||
|
node-key="agencyId"
|
||||||
|
lazy
|
||||||
|
:load="loadTreeNode"
|
||||||
|
@node-click="handleNodeClick"
|
||||||
|
>
|
||||||
|
<template #default="{ node, data: nodeData }">
|
||||||
|
<span class="custom-tree-node">
|
||||||
|
<span class="node-label">{{ node.label }}</span>
|
||||||
|
<span class="node-code">{{ nodeData.agencyCode }}</span>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-tree>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 右侧列表 -->
|
||||||
|
<div class="agency-list">
|
||||||
|
<BusinessTable
|
||||||
|
ref="busiTable"
|
||||||
|
v-loading="tableConfig.tableLoading"
|
||||||
|
:data-res="data"
|
||||||
|
:config="tableConfig"
|
||||||
|
:query-params="qp"
|
||||||
|
:permissions="perms"
|
||||||
|
@do-query="mergeActions.query"
|
||||||
|
@show-modify="mergeActions.modify"
|
||||||
|
@show-detail="mergeActions.detail"
|
||||||
|
@do-remove="mergeActions.remove"
|
||||||
|
@table-selection="mergeActions.handleSelectionChange"
|
||||||
|
@do-customize="mergeActions.doCustomize"
|
||||||
|
@query-params="mergeActions.updateQueryParams"
|
||||||
|
>
|
||||||
|
<el-table-column prop="agencyName" label="机构名称" min-width="200" show-overflow-tooltip />
|
||||||
|
<el-table-column prop="agencyCode" label="机构代码" min-width="150" />
|
||||||
|
<el-table-column prop="agencySimpleCode" label="机构简码" min-width="120" />
|
||||||
|
<el-table-column prop="agencyLevel" label="机构级别" min-width="100" align="center" />
|
||||||
|
<el-table-column prop="orderNum" label="排序号" min-width="100" align="center" />
|
||||||
|
</BusinessTable>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 对话框内容 -->
|
||||||
|
<template #dialogContent="{ dialogConfig: dc }">
|
||||||
|
<el-row :gutter="20">
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item label="机构名称" prop="agencyName">
|
||||||
|
<el-input
|
||||||
|
:disabled="dc.mode === 'detail'"
|
||||||
|
v-model="dc.data.agencyName"
|
||||||
|
placeholder="请输入机构名称"
|
||||||
|
maxlength="255"
|
||||||
|
show-word-limit
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item label="机构代码" prop="agencyCode">
|
||||||
|
<el-input
|
||||||
|
:disabled="dc.mode === 'detail'"
|
||||||
|
v-model="dc.data.agencyCode"
|
||||||
|
placeholder="请输入机构代码"
|
||||||
|
maxlength="17"
|
||||||
|
show-word-limit
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item label="机构简码" prop="agencySimpleCode">
|
||||||
|
<el-input
|
||||||
|
disabled
|
||||||
|
v-model="dc.data.agencySimpleCode"
|
||||||
|
placeholder="自动生成"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item label="上级机构" prop="parent">
|
||||||
|
<AgencySelector
|
||||||
|
v-model="dc.data.parent"
|
||||||
|
:disabled="dc.mode === 'detail'"
|
||||||
|
placeholder="请选择上级机构(不选则为根节点)"
|
||||||
|
:lazy-load="true"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="排序号" prop="orderNum">
|
||||||
|
<el-input-number
|
||||||
|
:disabled="dc.mode === 'detail'"
|
||||||
|
v-model="dc.data.orderNum"
|
||||||
|
:min="0"
|
||||||
|
controls-position="right"
|
||||||
|
style="width: 100%"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12" v-if="dc.mode === 'detail'">
|
||||||
|
<el-form-item label="机构级别" prop="agencyLevel">
|
||||||
|
<el-input :disabled="true" v-model="dc.data.agencyLevel" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12" v-if="dc.mode === 'detail'">
|
||||||
|
<el-form-item label="是否叶子节点" prop="leaf">
|
||||||
|
<el-tag :type="dc.data.leaf ? 'success' : 'info'" size="small">
|
||||||
|
{{ dc.data.leaf ? '是' : '否' }}
|
||||||
|
</el-tag>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12" v-if="dc.mode === 'detail'">
|
||||||
|
<el-form-item label="机构路径" prop="agencyPath">
|
||||||
|
<el-input :disabled="true" v-model="dc.data.agencyPath" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</template>
|
||||||
|
</browser>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { reactive, toRefs, ref, onMounted, nextTick, watch } from 'vue'
|
||||||
|
import { Refresh } from '@element-plus/icons-vue'
|
||||||
|
import Browser from '@/components/Browser.vue'
|
||||||
|
import BusinessTable from '@/components/BusinessTable.vue'
|
||||||
|
import AgencySelector from '@/components/AgencySelector.vue'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import agencies from '@/api/lawenforcement/Agency.js'
|
||||||
|
|
||||||
|
// 组件引用
|
||||||
|
const treeRef = ref(null)
|
||||||
|
const busiTable = ref(null)
|
||||||
|
|
||||||
|
// 状态管理
|
||||||
|
const state = reactive({
|
||||||
|
componentLoading: false,
|
||||||
|
treeLoading: false,
|
||||||
|
treeData: [], // 用于懒加载树的数据(空数组)
|
||||||
|
currentNode: null, // 当前选中的树节点
|
||||||
|
permissions: {
|
||||||
|
query: true,
|
||||||
|
add: true,
|
||||||
|
modify: true,
|
||||||
|
detail: true,
|
||||||
|
delete: true,
|
||||||
|
deleteAll: true,
|
||||||
|
importFile: false,
|
||||||
|
exportFile: false,
|
||||||
|
exportSelectFile: false,
|
||||||
|
downloadTemp: false,
|
||||||
|
canDeleteCustom: (row) => {
|
||||||
|
// 只有叶子节点才能删除
|
||||||
|
return row.leaf === true
|
||||||
|
},
|
||||||
|
canModifyCustom: () => {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
tableConfig: {
|
||||||
|
hasControlColumn: true,
|
||||||
|
controlWidth: '180',
|
||||||
|
tableLoading: false,
|
||||||
|
selectable: (row) => {
|
||||||
|
// 只有叶子节点才能被选中批量删除
|
||||||
|
return row.leaf === true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
apiConfig: {
|
||||||
|
api: agencies,
|
||||||
|
modelId: 'agencyId',
|
||||||
|
},
|
||||||
|
dialogConfig: {
|
||||||
|
type: 'min',
|
||||||
|
show: false,
|
||||||
|
mode: 'detail',
|
||||||
|
formLabelWidth: '120px',
|
||||||
|
baseTitle: '执法机构',
|
||||||
|
loading: false,
|
||||||
|
rules: {
|
||||||
|
agencyName: [
|
||||||
|
{ required: true, message: '机构名称不能为空', trigger: 'blur' },
|
||||||
|
{ min: 1, max: 255, message: '机构名称长度为1-255个字符', trigger: 'blur' }
|
||||||
|
],
|
||||||
|
agencyCode: [
|
||||||
|
{ required: true, message: '机构代码不能为空', trigger: 'blur' },
|
||||||
|
{ min: 1, max: 17, message: '机构代码长度为1-17个字符', trigger: 'blur' }
|
||||||
|
],
|
||||||
|
agencySimpleCode: [
|
||||||
|
{ min: 0, max: 17, message: '机构简码长度不能超过17个字符', trigger: 'blur' }
|
||||||
|
],
|
||||||
|
orderNum: [
|
||||||
|
{ type: 'number', message: '排序号必须为数字', trigger: 'blur' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
data: {},
|
||||||
|
actions: {}
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
add: handleAdd,
|
||||||
|
startQuery: handleStartQuery
|
||||||
|
},
|
||||||
|
queryParams: {
|
||||||
|
parentId: null // 根据选中的树节点查询子机构
|
||||||
|
},
|
||||||
|
treeProps: {
|
||||||
|
label: 'agencyName',
|
||||||
|
children: 'children',
|
||||||
|
value: 'agencyId',
|
||||||
|
isLeaf: 'leaf'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const {
|
||||||
|
componentLoading,
|
||||||
|
treeLoading,
|
||||||
|
treeData,
|
||||||
|
currentNode,
|
||||||
|
permissions,
|
||||||
|
tableConfig,
|
||||||
|
apiConfig,
|
||||||
|
dialogConfig,
|
||||||
|
actions,
|
||||||
|
queryParams,
|
||||||
|
treeProps
|
||||||
|
} = toRefs(state)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成机构简码:从左到右每两位一组,保留非"00"分组,去掉末尾连续为0的分组
|
||||||
|
* 例如:610113000000 -> 610113(去掉末尾3个"00")
|
||||||
|
* 例如:01610198017000000 -> 016101980170(去掉末尾3个"00")
|
||||||
|
*/
|
||||||
|
function generateSimpleCode(agencyCode) {
|
||||||
|
if (!agencyCode) return ''
|
||||||
|
|
||||||
|
const code = String(agencyCode)
|
||||||
|
const groups = []
|
||||||
|
// 从左到右按两位分组,最后一组可能为1位
|
||||||
|
for (let i = 0; i < code.length; i += 2) {
|
||||||
|
groups.push(code.slice(i, i + 2))
|
||||||
|
}
|
||||||
|
// 去掉末尾为全0的分组:'00' 或 单独的 '0'
|
||||||
|
while (groups.length > 0) {
|
||||||
|
const last = groups[groups.length - 1]
|
||||||
|
if (last === '00' || last === '0') {
|
||||||
|
groups.pop()
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return groups.join('')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 组件挂载时的初始化
|
||||||
|
onMounted(() => {
|
||||||
|
// 使用lazy模式时,树会自动调用load函数加载根节点
|
||||||
|
// 等待树加载完成后自动展开第一级节点
|
||||||
|
nextTick(() => {
|
||||||
|
setTimeout(() => {
|
||||||
|
if (treeRef.value) {
|
||||||
|
const rootNodes = treeRef.value.store.root.childNodes
|
||||||
|
rootNodes.forEach(node => {
|
||||||
|
node.expand()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, 500)
|
||||||
|
})
|
||||||
|
|
||||||
|
// 监听对话框中的机构代码变化,自动生成简码
|
||||||
|
watch(
|
||||||
|
() => dialogConfig.value.data.agencyCode,
|
||||||
|
(newCode) => {
|
||||||
|
if (newCode) {
|
||||||
|
dialogConfig.value.data.agencySimpleCode = generateSimpleCode(newCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 懒加载树节点的子节点
|
||||||
|
* @param {Object} node - 当前节点
|
||||||
|
* @param {Function} resolve - 回调函数,传入子节点数据
|
||||||
|
*/
|
||||||
|
async function loadTreeNode(node, resolve) {
|
||||||
|
// 如果是根节点,加载根级机构
|
||||||
|
if (node.level === 0) {
|
||||||
|
try {
|
||||||
|
const res = await agencies.querylist({ parentId: '0' })
|
||||||
|
if (res.success) {
|
||||||
|
resolve(res.data || [])
|
||||||
|
} else {
|
||||||
|
ElMessage.error(res.message || '加载机构失败')
|
||||||
|
resolve([])
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('加载机构失败:', error)
|
||||||
|
ElMessage.error('加载机构失败')
|
||||||
|
resolve([])
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 加载子机构
|
||||||
|
try {
|
||||||
|
const res = await agencies.querylist({ parentId: node.data.agencyId })
|
||||||
|
if (res.success) {
|
||||||
|
resolve(res.data || [])
|
||||||
|
} else {
|
||||||
|
ElMessage.error(res.message || '加载子机构失败')
|
||||||
|
resolve([])
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('加载子机构失败:', error)
|
||||||
|
ElMessage.error('加载子机构失败')
|
||||||
|
resolve([])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 刷新树形数据
|
||||||
|
* 懒加载模式下,需要重置树的store状态
|
||||||
|
*/
|
||||||
|
function refreshTree() {
|
||||||
|
const tree = treeRef.value
|
||||||
|
if (tree) {
|
||||||
|
treeLoading.value = true
|
||||||
|
// 清空当前节点选择
|
||||||
|
tree.setCurrentKey(null)
|
||||||
|
currentNode.value = null
|
||||||
|
|
||||||
|
// 获取所有根节点并移除
|
||||||
|
const rootNodes = tree.store.root.childNodes
|
||||||
|
rootNodes.forEach(node => {
|
||||||
|
tree.store.root.removeChild(node)
|
||||||
|
})
|
||||||
|
|
||||||
|
// 重新加载根节点
|
||||||
|
loadTreeNode(tree.store.root, (data) => {
|
||||||
|
data.forEach(nodeData => {
|
||||||
|
tree.store.root.insertChild({ data: nodeData })
|
||||||
|
})
|
||||||
|
treeLoading.value = false
|
||||||
|
|
||||||
|
// 自动展开第一级节点
|
||||||
|
nextTick(() => {
|
||||||
|
setTimeout(() => {
|
||||||
|
const newRootNodes = tree.store.root.childNodes
|
||||||
|
newRootNodes.forEach(node => {
|
||||||
|
node.expand()
|
||||||
|
})
|
||||||
|
}, 100)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// 清空右侧列表的查询参数
|
||||||
|
queryParams.value.parentId = null
|
||||||
|
nextTick(() => {
|
||||||
|
if (busiTable.value && busiTable.value.resetQuery) {
|
||||||
|
busiTable.value.resetQuery()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理初始查询
|
||||||
|
* 由于使用了自定义table插槽,需要确保busiTable已挂载
|
||||||
|
*/
|
||||||
|
function handleStartQuery() {
|
||||||
|
nextTick(() => {
|
||||||
|
if (busiTable.value && busiTable.value.resetQuery) {
|
||||||
|
busiTable.value.resetQuery()
|
||||||
|
}
|
||||||
|
const parentId = queryParams.value?.parentId
|
||||||
|
if (actions.value && actions.value.query && parentId !== null && parentId !== undefined && parentId !== '') {
|
||||||
|
actions.value.query()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 树节点点击事件
|
||||||
|
* @param {Object} data - 节点数据
|
||||||
|
*/
|
||||||
|
function handleNodeClick(data) {
|
||||||
|
currentNode.value = data
|
||||||
|
// 设置查询参数为当前节点的ID,查询其子机构
|
||||||
|
queryParams.value.parentId = data.agencyId
|
||||||
|
// 使用nextTick确保queryParams更新后再触发查询
|
||||||
|
nextTick(() => {
|
||||||
|
if (busiTable.value && busiTable.value.resetQuery) {
|
||||||
|
busiTable.value.resetQuery()
|
||||||
|
// 重置后立即触发查询
|
||||||
|
if (actions.value && actions.value.query) {
|
||||||
|
actions.value.query()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增机构处理
|
||||||
|
*/
|
||||||
|
async function handleAdd() {
|
||||||
|
dialogConfig.value.mode = 'add'
|
||||||
|
dialogConfig.value.title = '新增执法机构'
|
||||||
|
// 如果选中了树节点,则新增的机构为该节点的子机构
|
||||||
|
// 否则新增为根机构(parent为null)
|
||||||
|
const parent = currentNode.value ? currentNode.value : null
|
||||||
|
|
||||||
|
// 获取下一个排序号
|
||||||
|
let orderNum = 0
|
||||||
|
try {
|
||||||
|
const parentId = parent ? parent.agencyId : '0'
|
||||||
|
const res = await agencies.getNextOrderNum(parentId)
|
||||||
|
if (res.success && res.data !== null && res.data !== undefined) {
|
||||||
|
orderNum = res.data
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取排序号失败:', error)
|
||||||
|
orderNum = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
dialogConfig.value.data = {
|
||||||
|
agencyId: null,
|
||||||
|
agencyName: '',
|
||||||
|
agencyCode: '',
|
||||||
|
agencySimpleCode: '',
|
||||||
|
agencyLevel: null,
|
||||||
|
leaf: true,
|
||||||
|
orderNum: orderNum,
|
||||||
|
agencyPath: '',
|
||||||
|
parent: parent,
|
||||||
|
children: []
|
||||||
|
}
|
||||||
|
dialogConfig.value.show = true
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.agency-content {
|
||||||
|
display: flex;
|
||||||
|
height: 100%;
|
||||||
|
gap: 8px;
|
||||||
|
padding-top: 8px;
|
||||||
|
overflow: hidden;
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
|
.agency-tree {
|
||||||
|
width: 300px;
|
||||||
|
min-width: 300px;
|
||||||
|
max-width: 300px;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 16px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.tree-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
padding-bottom: 12px;
|
||||||
|
border-bottom: 1px solid #e8e8e8;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
.tree-title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-tree) {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-tree-node {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex: 1;
|
||||||
|
padding: 4px 0;
|
||||||
|
|
||||||
|
.node-label {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #333;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.node-code {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-tree-node__content) {
|
||||||
|
height: auto;
|
||||||
|
min-height: 40px;
|
||||||
|
padding: 4px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-tree-node__label) {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.agency-list {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 8px;
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
:deep(.business-table) {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 响应式设计
|
||||||
|
@media (max-width: 1200px) {
|
||||||
|
.agency-content {
|
||||||
|
.agency-tree {
|
||||||
|
width: 250px;
|
||||||
|
min-width: 250px;
|
||||||
|
max-width: 250px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,271 @@
|
||||||
|
<template>
|
||||||
|
<browser
|
||||||
|
:component-loading="componentLoading"
|
||||||
|
:api-config="apiConfig"
|
||||||
|
:table-config="tableConfig"
|
||||||
|
:permissions="permissions"
|
||||||
|
:dialog-config="dialogConfig"
|
||||||
|
:actions="actions"
|
||||||
|
:default-query-params="queryParams"
|
||||||
|
@update:query-params="queryParams = $event"
|
||||||
|
@update:actions="actions = $event"
|
||||||
|
@update:dialog-config="dialogConfig = $event"
|
||||||
|
>
|
||||||
|
<template #queryPanel="{ queryParams: qp }">
|
||||||
|
<el-form :model="qp" label-width="100px">
|
||||||
|
<el-row class="query-condition">
|
||||||
|
<el-col :span="6">
|
||||||
|
<el-form-item label="姓名" prop="officerName">
|
||||||
|
<el-input v-model="qp.officerName" placeholder="请输入姓名" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="6">
|
||||||
|
<el-form-item label="执法号" prop="lawNo">
|
||||||
|
<el-input v-model="qp.lawNo" placeholder="请输入执法号" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="6">
|
||||||
|
<el-form-item label="联系电话" prop="contactPhone">
|
||||||
|
<el-input v-model="qp.contactPhone" placeholder="请输入联系电话" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="6">
|
||||||
|
<el-form-item label="系统用户ID" prop="certificateNo">
|
||||||
|
<el-input v-model="qp.certificateNo" placeholder="请输入系统用户ID" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<el-table-column prop="officerName" label="姓名" min-width="140" show-overflow-tooltip />
|
||||||
|
<el-table-column prop="lawNo" label="执法号" min-width="140" />
|
||||||
|
<el-table-column prop="contactPhone" label="联系电话" min-width="140" />
|
||||||
|
<el-table-column prop="agencyName" label="机构名称" min-width="180" />
|
||||||
|
<el-table-column prop="certificateNo" label="系统用户ID" min-width="160" />
|
||||||
|
|
||||||
|
<template #dialogContent="{ dialogConfig: dc }">
|
||||||
|
<el-row :gutter="20">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="姓名" prop="officerName">
|
||||||
|
<el-input :disabled="dc.mode === 'detail'" v-model="dc.data.officerName" placeholder="请输入姓名" maxlength="100" show-word-limit />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="执法号" prop="lawNo">
|
||||||
|
<el-input :disabled="dc.mode === 'detail'" v-model="dc.data.lawNo" placeholder="请输入执法号" maxlength="50" show-word-limit />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="联系电话" prop="contactPhone">
|
||||||
|
<el-input :disabled="dc.mode === 'detail'" v-model="dc.data.contactPhone" placeholder="请输入联系电话" maxlength="20" show-word-limit />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="系统用户ID" prop="certificateNo">
|
||||||
|
<el-input :disabled="dc.mode === 'detail'" v-model="dc.data.certificateNo" placeholder="请输入系统用户ID" maxlength="50" show-word-limit />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item label="所属机构" prop="agency">
|
||||||
|
<AgencySelector v-model="dc.data.agency" :disabled="dc.mode === 'detail'" placeholder="请选择机构" :lazy-load="true" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</template>
|
||||||
|
</browser>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { reactive, toRefs, ref } from 'vue'
|
||||||
|
import Browser from '@/components/Browser.vue'
|
||||||
|
import BusinessTable from '@/components/BusinessTable.vue'
|
||||||
|
import AgencySelector from '@/components/AgencySelector.vue'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import officers from '@/api/lawenforcement/Officer.js'
|
||||||
|
import agencies from '@/api/lawenforcement/Agency.js'
|
||||||
|
|
||||||
|
const busiTable = ref(null)
|
||||||
|
|
||||||
|
const phoneValidator = (rule, value, callback) => {
|
||||||
|
if (!value) return callback()
|
||||||
|
const mobile = /^(?:\+?86)?1[3-9]\d{9}$/
|
||||||
|
const landline = /^(\d{3,4}-?)?\d{7,8}$/
|
||||||
|
if (mobile.test(value) || landline.test(value)) return callback()
|
||||||
|
callback(new Error('联系电话格式不正确'))
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleDialogOk(formRef) {
|
||||||
|
const doValidate = () => new Promise((resolve) => {
|
||||||
|
if (!formRef) return resolve(true)
|
||||||
|
formRef.validate((valid) => resolve(valid))
|
||||||
|
})
|
||||||
|
const valid = await doValidate()
|
||||||
|
if (!valid) return
|
||||||
|
dialogConfig.value.loading = true
|
||||||
|
let res
|
||||||
|
try {
|
||||||
|
const payload = { ...dialogConfig.value.data }
|
||||||
|
payload.agencyId = payload.agency?.agencyId || payload.agencyId || null
|
||||||
|
delete payload.agency
|
||||||
|
if (dialogConfig.value.mode === 'add') {
|
||||||
|
res = await officers.add(payload)
|
||||||
|
} else if (dialogConfig.value.mode === 'modify') {
|
||||||
|
res = await officers.modify(payload[apiConfig.value.modelId], payload)
|
||||||
|
}
|
||||||
|
if (res?.success) {
|
||||||
|
dialogConfig.value.loading = false
|
||||||
|
dialogConfig.value.show = false
|
||||||
|
actions.value.query()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
throw new Error('操作失败')
|
||||||
|
} catch (e) {
|
||||||
|
ElMessage.error(e.message || '操作失败')
|
||||||
|
} finally {
|
||||||
|
dialogConfig.value.loading = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const state = reactive({
|
||||||
|
componentLoading: false,
|
||||||
|
permissions: {
|
||||||
|
query: true,
|
||||||
|
add: true,
|
||||||
|
modify: true,
|
||||||
|
detail: true,
|
||||||
|
delete: true,
|
||||||
|
deleteAll: true,
|
||||||
|
importFile: false,
|
||||||
|
exportFile: false,
|
||||||
|
exportSelectFile: false,
|
||||||
|
downloadTemp: false,
|
||||||
|
canDeleteCustom: () => true,
|
||||||
|
canModifyCustom: () => true,
|
||||||
|
canDetailCustom: () => true,
|
||||||
|
},
|
||||||
|
tableConfig: {
|
||||||
|
hasControlColumn: true,
|
||||||
|
controlWidth: '220',
|
||||||
|
tableLoading: false,
|
||||||
|
multipleSelect: true,
|
||||||
|
},
|
||||||
|
apiConfig: {
|
||||||
|
api: officers,
|
||||||
|
modelId: 'officerId',
|
||||||
|
},
|
||||||
|
dialogConfig: {
|
||||||
|
type: 'min',
|
||||||
|
show: false,
|
||||||
|
mode: 'detail',
|
||||||
|
formLabelWidth: '120px',
|
||||||
|
baseTitle: '执法人员',
|
||||||
|
loading: false,
|
||||||
|
rules: {
|
||||||
|
officerName: [
|
||||||
|
{ required: true, message: '姓名不能为空', trigger: 'blur' },
|
||||||
|
{ min: 1, max: 100, message: '姓名长度为1-100个字符', trigger: 'blur' }
|
||||||
|
],
|
||||||
|
lawNo: [
|
||||||
|
{ required: true, message: '执法号不能为空', trigger: 'blur' },
|
||||||
|
{ min: 1, max: 50, message: '执法号长度为1-50个字符', trigger: 'blur' }
|
||||||
|
],
|
||||||
|
contactPhone: [
|
||||||
|
{ validator: phoneValidator, trigger: 'blur' },
|
||||||
|
{ min: 0, max: 20, message: '联系电话长度不能超过20个字符', trigger: 'blur' }
|
||||||
|
],
|
||||||
|
certificateNo: [
|
||||||
|
{ min: 0, max: 50, message: '系统用户ID长度不能超过50个字符', trigger: 'blur' }
|
||||||
|
],
|
||||||
|
agency: [
|
||||||
|
{ required: true, message: '所属机构不能为空', trigger: 'change' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
data: {},
|
||||||
|
actions: { handleDialogOk }
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
add: handleAdd,
|
||||||
|
detail: handleDetail,
|
||||||
|
modify: handleModify,
|
||||||
|
},
|
||||||
|
queryParams: {}
|
||||||
|
})
|
||||||
|
|
||||||
|
const {
|
||||||
|
componentLoading,
|
||||||
|
permissions,
|
||||||
|
tableConfig,
|
||||||
|
apiConfig,
|
||||||
|
dialogConfig,
|
||||||
|
actions,
|
||||||
|
queryParams,
|
||||||
|
} = toRefs(state)
|
||||||
|
|
||||||
|
async function handleAdd() {
|
||||||
|
dialogConfig.value.mode = 'add'
|
||||||
|
dialogConfig.value.title = '新增执法人员'
|
||||||
|
dialogConfig.value.data = {
|
||||||
|
officerId: null,
|
||||||
|
officerName: '',
|
||||||
|
lawNo: '',
|
||||||
|
contactPhone: '',
|
||||||
|
certificateNo: '',
|
||||||
|
agencyId: null,
|
||||||
|
agency: null,
|
||||||
|
}
|
||||||
|
dialogConfig.value.show = true
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleDetail(row) {
|
||||||
|
dialogConfig.value.data = {}
|
||||||
|
dialogConfig.value.title = '详情执法人员'
|
||||||
|
dialogConfig.value.show = true
|
||||||
|
dialogConfig.value.mode = 'detail'
|
||||||
|
dialogConfig.value.showFooter = false
|
||||||
|
dialogConfig.value.loading = true
|
||||||
|
try {
|
||||||
|
const res = await officers.findOne(row[apiConfig.value.modelId])
|
||||||
|
if (!res?.success) throw new Error('接口返回数据异常')
|
||||||
|
const data = res.data || {}
|
||||||
|
if (!data.agency && data.agencyId) {
|
||||||
|
try {
|
||||||
|
const a = await agencies.findOne(data.agencyId)
|
||||||
|
if (a?.success) data.agency = a.data
|
||||||
|
} catch (_) {}
|
||||||
|
}
|
||||||
|
dialogConfig.value.data = data
|
||||||
|
} catch (e) {
|
||||||
|
ElMessage.error(e.message || '详情加载失败')
|
||||||
|
} finally {
|
||||||
|
dialogConfig.value.loading = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleModify(row) {
|
||||||
|
dialogConfig.value.data = {}
|
||||||
|
dialogConfig.value.title = '修改执法人员'
|
||||||
|
dialogConfig.value.show = true
|
||||||
|
dialogConfig.value.mode = 'modify'
|
||||||
|
dialogConfig.value.loading = true
|
||||||
|
try {
|
||||||
|
const res = await officers.findOne(row[apiConfig.value.modelId])
|
||||||
|
if (!res?.success) throw new Error('接口返回数据异常')
|
||||||
|
const data = res.data || {}
|
||||||
|
if (!data.agency && data.agencyId) {
|
||||||
|
try {
|
||||||
|
const a = await agencies.findOne(data.agencyId)
|
||||||
|
if (a?.success) data.agency = a.data
|
||||||
|
} catch (_) {}
|
||||||
|
}
|
||||||
|
dialogConfig.value.data = data
|
||||||
|
} catch (e) {
|
||||||
|
ElMessage.error(e.message || '详情加载失败')
|
||||||
|
} finally {
|
||||||
|
dialogConfig.value.loading = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,185 @@
|
||||||
|
<template>
|
||||||
|
<browser :component-loading="componentLoading"
|
||||||
|
:api-config="apiConfig"
|
||||||
|
:table-config="tableConfig"
|
||||||
|
:permissions="permissions"
|
||||||
|
:dialog-config="dialogConfig"
|
||||||
|
:actions="actions"
|
||||||
|
:default-query-params="queryParams"
|
||||||
|
@update:query-params="queryParams = $event"
|
||||||
|
@update:actions="actions = $event"
|
||||||
|
@update:dialog-config="dialogConfig = $event">
|
||||||
|
<template #queryPanel="{ queryParams: qp }">
|
||||||
|
<el-form ref="queryForm" :model="qp" label-width="100px">
|
||||||
|
<el-row class="query-condition">
|
||||||
|
<el-col :span="6">
|
||||||
|
<el-form-item label="方式名称" prop="methodName">
|
||||||
|
<el-input v-model="qp.methodName"/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="6">
|
||||||
|
<el-form-item label="方式描述" prop="description">
|
||||||
|
<el-input v-model="qp.description"/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="6">
|
||||||
|
<el-form-item label="是否删除" prop="isDeleted">
|
||||||
|
<el-select v-model="qp.isDeleted" placeholder="请选择" clearable>
|
||||||
|
<el-option v-for="item in DICTITEMS.SF_OPTIONS" :key="item.value" :label="item.label"
|
||||||
|
:value="item.value"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form>
|
||||||
|
</template>
|
||||||
|
<el-table-column prop="methodName" label="方式名称" min-width="200"/>
|
||||||
|
<el-table-column prop="description" label="方式描述" min-width="500" show-overflow-tooltip/>
|
||||||
|
<el-table-column prop="enabled" label="启用状态" min-width="200">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-switch v-model="scope.row.enabled"
|
||||||
|
@change="updateEnabled(scope.row)"
|
||||||
|
:disabled="scope.row.isDeleted"
|
||||||
|
:active-value="true"
|
||||||
|
:inactive-value="false"
|
||||||
|
active-text="启用"
|
||||||
|
inactive-text="停用"
|
||||||
|
active-color="#13ce66"
|
||||||
|
inactive-color="#ff4949"/>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="createTime" label="创建时间" min-width="200"/>
|
||||||
|
<template #dialogContent="{ dialogConfig: dc }">
|
||||||
|
<el-row :disabled="true">
|
||||||
|
<el-col :span="16">
|
||||||
|
<el-form-item label="方式名称" prop="methodName">
|
||||||
|
<el-input :disabled="dc.mode === 'detail'" v-model="dc.data.methodName"/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item label="方式描述" prop="description">
|
||||||
|
<el-input :disabled="dc.mode === 'detail'" type="textarea" v-model="dc.data.description"/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-form-item label="是否启用" prop="enabled">
|
||||||
|
<el-switch :disabled="dc.mode === 'detail'" v-model="dc.data.enabled" :active-value="true"
|
||||||
|
:inactive-value="false" active-text="启用" inactive-text="停用" active-color="#13ce66"
|
||||||
|
inactive-color="#ff4949"/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-form-item v-if="dc.mode ==='detail'" label="更新时间" prop="updateTime">
|
||||||
|
<el-input :disabled="true" v-model="dc.data.updateTime"/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-form-item v-if="dc.mode ==='detail'" label="创建时间" prop="createTime">
|
||||||
|
<el-input :disabled="true" v-model="dc.data.createTime"/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</template>
|
||||||
|
</browser>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import {reactive, toRefs} from 'vue'
|
||||||
|
import Browser from '@/components/Browser.vue'
|
||||||
|
import {useUserStore} from '@/stores/modules/user'
|
||||||
|
import deliveryMethods from "@/api/lawenforcement/DeliveryMethod.js"
|
||||||
|
import {ElMessage} from "element-plus"
|
||||||
|
import {DICTITEMS} from "@/utils/Constants.js";
|
||||||
|
|
||||||
|
const userStore = useUserStore()
|
||||||
|
|
||||||
|
const state = reactive({
|
||||||
|
componentLoading: false,
|
||||||
|
permissions: {
|
||||||
|
query: true,
|
||||||
|
add: true,
|
||||||
|
modify: true,
|
||||||
|
detail: true,
|
||||||
|
delete: true,
|
||||||
|
deleteAll: true,
|
||||||
|
importFile: false,
|
||||||
|
exportFile: false,
|
||||||
|
exportSelectFile: false,
|
||||||
|
downloadTemp: false,
|
||||||
|
canDeleteCustom: (row) => {
|
||||||
|
return !row.isDeleted
|
||||||
|
},
|
||||||
|
canModifyCustom: (row) => {
|
||||||
|
return !row.isDeleted
|
||||||
|
}
|
||||||
|
},
|
||||||
|
tableConfig: {
|
||||||
|
hasControlColumn: true,
|
||||||
|
controlWidth: '150',
|
||||||
|
tableLoading: false
|
||||||
|
},
|
||||||
|
apiConfig: {
|
||||||
|
api: deliveryMethods,
|
||||||
|
modelId: 'deliveryMethodId',
|
||||||
|
},
|
||||||
|
dialogConfig: {
|
||||||
|
show: false,
|
||||||
|
mode: 'detail',
|
||||||
|
formLabelWidth: '110px',
|
||||||
|
baseTitle: '送达方式',
|
||||||
|
loading: false,
|
||||||
|
rules: {
|
||||||
|
methodName: [{required: true, message: '方式名称不能为空', trigger: 'change'}, {
|
||||||
|
min: 0,
|
||||||
|
max: 500,
|
||||||
|
message: '方式名称不能超过2',
|
||||||
|
trigger: 'change'
|
||||||
|
}],
|
||||||
|
description: [{min: 0, max: 2000, message: '方式描述不能超过100', trigger: 'change'}],
|
||||||
|
enabled: [{required: true, message: '是否启用不能为空', trigger: 'change'}]
|
||||||
|
},
|
||||||
|
data: {},
|
||||||
|
actions: {}
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
add: handleAdd
|
||||||
|
},
|
||||||
|
queryParams: {isDeleted: '0'}
|
||||||
|
})
|
||||||
|
|
||||||
|
const {
|
||||||
|
componentLoading,
|
||||||
|
permissions,
|
||||||
|
tableConfig,
|
||||||
|
apiConfig,
|
||||||
|
dialogConfig,
|
||||||
|
actions,
|
||||||
|
queryParams,
|
||||||
|
selectConfig
|
||||||
|
} = toRefs(state)
|
||||||
|
|
||||||
|
function handleAdd() {
|
||||||
|
dialogConfig.value.mode = 'add'
|
||||||
|
dialogConfig.value.title = '新增送达方式'
|
||||||
|
dialogConfig.value.data = {
|
||||||
|
enabled: true
|
||||||
|
}
|
||||||
|
dialogConfig.value.show = true
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateEnabled(row) {
|
||||||
|
tableConfig.value.tableLoading = true
|
||||||
|
apiConfig.value.api.modify(row[apiConfig.value.modelId], row).then(rs => {
|
||||||
|
tableConfig.value.tableLoading = false
|
||||||
|
actions.value.query()
|
||||||
|
if (rs.success) {
|
||||||
|
ElMessage.success('操作成功')
|
||||||
|
} else {
|
||||||
|
throw new Error('操作失败')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,174 @@
|
||||||
|
<template>
|
||||||
|
<browser :component-loading="componentLoading"
|
||||||
|
:api-config="apiConfig"
|
||||||
|
:table-config="tableConfig"
|
||||||
|
:permissions="permissions"
|
||||||
|
:dialog-config="dialogConfig"
|
||||||
|
:actions="actions"
|
||||||
|
:default-query-params="queryParams"
|
||||||
|
@update:query-params="queryParams = $event"
|
||||||
|
@update:dialog-config="dialogConfig = $event">
|
||||||
|
<template #queryPanel="{ queryParams: qp }">
|
||||||
|
<el-form ref="queryForm" :model="qp" label-width="80px">
|
||||||
|
<el-row class="query-condition">
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-form-item label="属地">
|
||||||
|
<AgencySelector v-model="qp.agency" :lazy-load="true"/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form>
|
||||||
|
</template>
|
||||||
|
<el-table-column header-align="center" align="center" type="index" label="序号" min-width="80"/>
|
||||||
|
<el-table-column header-align="center" align="center" prop="agencyName" label="属地" min-width="250"/>
|
||||||
|
<el-table-column header-align="center" align="center" label="总数" prop="total" min-width="150"
|
||||||
|
class-name="can-click"/>
|
||||||
|
<!-- 字段名,一定要放在第一行-->
|
||||||
|
<el-table-column header-align="center" align="center"
|
||||||
|
v-for="col in allCols"
|
||||||
|
:prop="col.deliveryMethodId"
|
||||||
|
:key="col.deliveryMethodId"
|
||||||
|
:label="col.methodName"
|
||||||
|
width="150"
|
||||||
|
class-name="can-click"/>
|
||||||
|
<template #dialog="{ dialogConfig: dc }">
|
||||||
|
<el-dialog :open="dc.show" :title="dc.title" :type="dc.type" v-if="dc.show" :show-footer="false"
|
||||||
|
@update:open="dc.show = false">
|
||||||
|
<zfwsxx :dialog-data="dc.data" :is-not-dialog="false" style="height: 600px;"/>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
</browser>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import {reactive, toRefs, ref, nextTick} from 'vue'
|
||||||
|
import Browser from '@/components/Browser.vue'
|
||||||
|
import deliveryMethods from "@/api/lawenforcement/DeliveryMethod.js"
|
||||||
|
import deliveryRecords from "@/api/lawenforcement/DeliveryRecord.js"
|
||||||
|
import AgencySelector from "@/components/AgencySelector.vue"
|
||||||
|
import ElDialog from "@/components/ElDialog/index.vue"
|
||||||
|
import Zfwsxx from "@pages/zfwssd/zfwsxx.vue"
|
||||||
|
|
||||||
|
const state = reactive({
|
||||||
|
componentLoading: false,
|
||||||
|
permissions: {
|
||||||
|
query: true,
|
||||||
|
add: false,
|
||||||
|
modify: false,
|
||||||
|
detail: false,
|
||||||
|
delete: false,
|
||||||
|
importFile: false,
|
||||||
|
exportFile: false,
|
||||||
|
exportSelectFile: false,
|
||||||
|
downloadTemp: false
|
||||||
|
},
|
||||||
|
tableConfig: {
|
||||||
|
tableData: [],
|
||||||
|
tableLoading: false,
|
||||||
|
usePage: false,
|
||||||
|
multipleSelect: false,
|
||||||
|
hasControlColumn: false,
|
||||||
|
controlWidth: '150',
|
||||||
|
lazy: true,
|
||||||
|
rowKey: 'agencyCode',
|
||||||
|
treeProps: {children: 'children', hasChildren: 'hasChildren'},
|
||||||
|
load: load,
|
||||||
|
cellClick: caseEventClick
|
||||||
|
},
|
||||||
|
apiConfig: {
|
||||||
|
tableLoading: false,
|
||||||
|
api: deliveryRecords,
|
||||||
|
modelId: 'deliveryId',
|
||||||
|
},
|
||||||
|
dialogConfig: {
|
||||||
|
show: false,
|
||||||
|
mode: 'detail',
|
||||||
|
loading: false,
|
||||||
|
data: {},
|
||||||
|
actions: {},
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
query: handleQuery
|
||||||
|
},
|
||||||
|
queryParams: {}
|
||||||
|
})
|
||||||
|
|
||||||
|
const allIds = ref([])
|
||||||
|
const allCols = ref([])
|
||||||
|
const {componentLoading, queryParams, permissions, tableConfig, apiConfig, dialogConfig, actions} = toRefs(state)
|
||||||
|
|
||||||
|
function handleQuery() {
|
||||||
|
tableConfig.value.tableLoading = true
|
||||||
|
if (queryParams.value.agency) {
|
||||||
|
queryParams.value = Object.assign({}, {
|
||||||
|
agencyCode: queryParams.value.agency.agencyCode,
|
||||||
|
agencyLevel: queryParams.value.agency.agencyLevel
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
queryParams.value = Object.assign({}, {
|
||||||
|
agencyCode: null,
|
||||||
|
agencyLevel: null
|
||||||
|
})
|
||||||
|
}
|
||||||
|
tableConfig.value.tableData = {success: true, data: [], total: 0}
|
||||||
|
nextTick(() => {
|
||||||
|
apiConfig.value.api.statistics(queryParams.value).then(res => {
|
||||||
|
if (res.success) {
|
||||||
|
tableConfig.value.tableData = res
|
||||||
|
}
|
||||||
|
tableConfig.value.tableLoading = false
|
||||||
|
}).catch(() => {
|
||||||
|
tableConfig.value.tableLoading = false
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function load(tree, treeNode, resolve) {
|
||||||
|
tableConfig.value.tableLoading = true
|
||||||
|
queryParams.value.agencyLevel = tree.agencyLevel + 1
|
||||||
|
queryParams.value.agencyCode = tree.agencyCode
|
||||||
|
apiConfig.value.api.statistics(queryParams.value).then(res => {
|
||||||
|
if (res.success) {
|
||||||
|
resolve(res.data)
|
||||||
|
}
|
||||||
|
tableConfig.value.tableLoading = false
|
||||||
|
}).catch(() => {
|
||||||
|
tableConfig.value.tableLoading = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function caseEventClick(row, column, cell, event) {
|
||||||
|
const colProp = column.property
|
||||||
|
let keys = allCols.value.map(o => o.deliveryMethodId)
|
||||||
|
keys.push('total')
|
||||||
|
if (keys.includes(colProp)) {
|
||||||
|
dialogConfig.value.show = true
|
||||||
|
dialogConfig.value.mode = 'detail'
|
||||||
|
dialogConfig.value.title = '执法文书列表'
|
||||||
|
dialogConfig.value.loading = false
|
||||||
|
let prop = colProp
|
||||||
|
if ('total' === colProp) prop = ''
|
||||||
|
dialogConfig.value.data = {deliveryMethodId: prop, agencyCode: row.agencyCode, show: false}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
tableConfig.value.tableLoading = true
|
||||||
|
deliveryMethods.querylist({isDeleted: false, enabled: true}).then(res => {
|
||||||
|
let arr = []
|
||||||
|
allIds.value = res.data.map(v => v.deliveryMethodId);
|
||||||
|
allIds.value.push('total')
|
||||||
|
allCols.value = [...res.data]
|
||||||
|
tableConfig.value.tableLoading = false
|
||||||
|
}).catch(() => {
|
||||||
|
tableConfig.value.tableLoading = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
init()
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,170 @@
|
||||||
|
<template>
|
||||||
|
<browser :component-loading="componentLoading"
|
||||||
|
:api-config="apiConfig"
|
||||||
|
:table-config="tableConfig"
|
||||||
|
:permissions="permissions"
|
||||||
|
:dialog-config="dialogConfig"
|
||||||
|
:actions="actions"
|
||||||
|
:default-query-params="queryParams"
|
||||||
|
@update:query-params="queryParams = $event"
|
||||||
|
@update:actions="actions = $event"
|
||||||
|
@update:dialog-config="dialogConfig = $event">
|
||||||
|
<template #queryPanel="{ queryParams: qp }">
|
||||||
|
<el-form ref="queryForm" :model="qp" label-width="100px">
|
||||||
|
<el-row class="query-condition">
|
||||||
|
<el-col :span="6">
|
||||||
|
<el-form-item label="姓名" prop="name">
|
||||||
|
<el-input v-model="qp.name" clearable/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="6">
|
||||||
|
<el-form-item label="联系电话" prop="phone">
|
||||||
|
<el-input v-model="qp.phone" clearable/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="6">
|
||||||
|
<el-form-item label="住址" prop="address">
|
||||||
|
<el-input v-model="qp.address" clearable/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="6">
|
||||||
|
<el-form-item label="是否删除" prop="isDeleted">
|
||||||
|
<el-select v-model="qp.isDeleted" placeholder="请选择" clearable>
|
||||||
|
<el-option v-for="item in DICTITEMS.SF_OPTIONS" :key="item.value" :label="item.label"
|
||||||
|
:value="item.value"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form>
|
||||||
|
</template>
|
||||||
|
<el-table-column prop="name" label="姓名" min-width="120"/>
|
||||||
|
<el-table-column prop="sexName" label="性别" sort-by="sex" min-width="120"/>
|
||||||
|
<el-table-column prop="phone" label="电话号码" min-width="150"/>
|
||||||
|
<el-table-column prop="email" label="电子邮件" min-width="160"/>
|
||||||
|
<el-table-column prop="wechatId" label="微信ID" min-width="150"/>
|
||||||
|
<el-table-column prop="address" label="住址" min-width="250"/>
|
||||||
|
<template #dialogContent="{ dialogConfig: dc }">
|
||||||
|
<el-row :disabled="true">
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-form-item label="姓名" prop="name">
|
||||||
|
<el-input :disabled="dc.mode === 'detail'" v-model="dc.data.name"/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-form-item label="性别" prop="sex">
|
||||||
|
<DictSelector :disabled="dc.mode === 'detail'" v-model="dc.data.sex" dict-code="DE01900" :multiple="false"/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-form-item label="电话号码" prop="phone">
|
||||||
|
<el-input :disabled="dc.mode === 'detail'" v-model="dc.data.phone"/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-form-item label="电子邮件" prop="email">
|
||||||
|
<el-input :disabled="dc.mode === 'detail'" v-model="dc.data.email"/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="16">
|
||||||
|
<el-form-item label="住址" prop="address">
|
||||||
|
<el-input :disabled="dc.mode === 'detail'" v-model="dc.data.address"/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-form-item label="微信ID" prop="wechatId">
|
||||||
|
<el-input :disabled="dc.mode === 'detail'" v-model="dc.data.wechatId"/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</template>
|
||||||
|
</browser>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import {reactive, toRefs} from 'vue'
|
||||||
|
import Browser from '@/components/Browser.vue'
|
||||||
|
import {useUserStore} from '@/stores/modules/user'
|
||||||
|
import recipientInfos from "@/api/lawenforcement/RecipientInfo.js";
|
||||||
|
import DictSelector from "@/components/DictSelector.vue";
|
||||||
|
import {DICTITEMS} from "@/utils/Constants.js";
|
||||||
|
|
||||||
|
const userStore = useUserStore()
|
||||||
|
|
||||||
|
const state = reactive({
|
||||||
|
componentLoading: false,
|
||||||
|
permissions: {
|
||||||
|
query: true,
|
||||||
|
add: true,
|
||||||
|
modify: true,
|
||||||
|
detail: true,
|
||||||
|
delete: true,
|
||||||
|
deleteAll: true,
|
||||||
|
importFile: false,
|
||||||
|
exportFile: false,
|
||||||
|
exportSelectFile: false,
|
||||||
|
downloadTemp: false,
|
||||||
|
canDeleteCustom: (row) => {
|
||||||
|
return !row.isDeleted
|
||||||
|
},
|
||||||
|
canModifyCustom: (row) => {
|
||||||
|
return !row.isDeleted
|
||||||
|
}
|
||||||
|
},
|
||||||
|
tableConfig: {
|
||||||
|
hasControlColumn: true,
|
||||||
|
controlWidth: '150',
|
||||||
|
tableLoading: false,
|
||||||
|
multipleSelect: true
|
||||||
|
},
|
||||||
|
apiConfig: {
|
||||||
|
api: recipientInfos,
|
||||||
|
modelId: 'recipientId'
|
||||||
|
},
|
||||||
|
dialogConfig: {
|
||||||
|
show: false,
|
||||||
|
mode: 'detail',
|
||||||
|
baseTitle: '受送人',
|
||||||
|
formLabelWidth: '90px',
|
||||||
|
loading: false,
|
||||||
|
rules: {
|
||||||
|
name: [
|
||||||
|
{required: true, message: '姓名不能为空', trigger: 'change'},
|
||||||
|
{min: 0, max: 30, message: '姓名不能超过30', trigger: 'change'}
|
||||||
|
],
|
||||||
|
sex: [{required: true, message: '性别不能为空', trigger: 'change'}],
|
||||||
|
phone: [
|
||||||
|
{required: true, message: '电话号码不能为空', trigger: 'change'},
|
||||||
|
{min: 0, max: 20, message: '电话号码不能超过20', trigger: 'change'},
|
||||||
|
{pattern: /^1[3-9]\d{9}$/, message: '请输入有效的电话号码', trigger: 'blur'}
|
||||||
|
],
|
||||||
|
email: [
|
||||||
|
{required: true, message: '电子邮件不能为空', trigger: 'change'},
|
||||||
|
{min: 0, max: 30, message: '电子邮件不能超过30', trigger: 'change'},
|
||||||
|
{
|
||||||
|
pattern: /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,
|
||||||
|
message: '请输入有效的电子邮件地址',
|
||||||
|
trigger: 'blur'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
address: [
|
||||||
|
{required: true, message: '住址不能为空', trigger: 'change'},
|
||||||
|
{min: 0, max: 200, message: '住址不能超过200', trigger: 'change'}
|
||||||
|
],
|
||||||
|
wechatId: [
|
||||||
|
{required: true, message: '微信ID不能为空', trigger: 'change'},
|
||||||
|
{min: 0, max: 50, message: '微信ID不能超过50', trigger: 'change'}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
data: {},
|
||||||
|
actions: {}
|
||||||
|
},
|
||||||
|
actions: {},
|
||||||
|
queryParams: {isDeleted: '0'}
|
||||||
|
})
|
||||||
|
|
||||||
|
const {componentLoading, permissions, tableConfig, apiConfig, dialogConfig, actions, queryParams} = toRefs(state)
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,478 @@
|
||||||
|
<template>
|
||||||
|
<browser :component-loading="componentLoading"
|
||||||
|
:api-config="apiConfig"
|
||||||
|
:table-config="tableConfig"
|
||||||
|
:permissions="permissions"
|
||||||
|
:dialog-config="dialogConfig"
|
||||||
|
:actions="actions"
|
||||||
|
@update:query-params="queryParams = $event"
|
||||||
|
@update:actions="actions = $event"
|
||||||
|
@update:dialog-config="dialogConfig = $event">
|
||||||
|
<template #extraButton v-if="isNotDialog">
|
||||||
|
<el-button type="success" @click="handleSms" :disabled="deliverys.length === 0">
|
||||||
|
<template #icon>
|
||||||
|
<font-awesome-icon icon="file-export"/>
|
||||||
|
</template>
|
||||||
|
短信推送 ({{ deliverys.length }})
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
<template #queryPanel="{ queryParams: qp }" v-if="isNotDialog">
|
||||||
|
<el-form ref="queryForm" :model="qp" label-width="80px">
|
||||||
|
<el-row class="query-condition">
|
||||||
|
<el-col :span="6">
|
||||||
|
<el-form-item label="案卷名称">
|
||||||
|
<SimpleEntitySelector v-model="qp.caseId" :simpleConfig="simpleConfigCase"/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="6">
|
||||||
|
<el-form-item label="受送达人">
|
||||||
|
<SimpleEntitySelector v-model="qp.recipientId" :simpleConfig="simpleConfigSdfs"/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="6">
|
||||||
|
<el-form-item label="送达方式">
|
||||||
|
<SimpleEntitySelector v-model="qp.deliveryMethodId" :simpleConfig="simpleConfigSsr"/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form>
|
||||||
|
</template>
|
||||||
|
<el-table-column prop="caseInfo.caseNum" label="案卷编号" min-width="200"/>
|
||||||
|
<el-table-column prop="caseInfo.caseName" label="案卷名称" min-width="350" show-overflow-tooltip/>
|
||||||
|
<el-table-column prop="documentInfo.documentName" label="文书名称" min-width="200"/>
|
||||||
|
<el-table-column prop="deliveryMethod.methodName" label="送达方式" min-width="100"/>
|
||||||
|
<el-table-column prop="recipientInfo.name" label="受送人" min-width="100"/>
|
||||||
|
<el-table-column prop="deliveryTime" label="实际送达时间" min-width="150"/>
|
||||||
|
<el-table-column prop="status" label="状态" min-width="100">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<span v-if="row.status!=='1'">正常送达</span><span v-else>留置送达</span></template>
|
||||||
|
</el-table-column>
|
||||||
|
<template #tableControlColumn="{data: r}">
|
||||||
|
<el-link v-if="r.data.row.needCll && isNotDialog" type="primary" @click="handleVoicePush(r.data.row)"
|
||||||
|
title="语音推送">语音推送
|
||||||
|
</el-link>
|
||||||
|
</template>
|
||||||
|
<template #dialogContent="{ dialogConfig: dc }">
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item label="案卷名称" prop="caseId">
|
||||||
|
<SimpleEntitySelector :disabled="dc.mode === 'detail'" @change="ajxxChange" v-model="dc.data.caseId"
|
||||||
|
:simpleConfig="simpleConfigCase"/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item label="执法文书" prop="documentId">
|
||||||
|
<SimpleEntitySelector :disabled="dc.mode === 'detail'" v-model="dc.data.documentId"
|
||||||
|
:simpleConfig="simpleConfigZfws" :caseId="dc.data.caseId"/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-form-item label="受送达人" prop="recipientId">
|
||||||
|
<SimpleEntitySelector :disabled="dc.mode === 'detail'" :simpleConfig="simpleConfigSdfs" :multiple="false"
|
||||||
|
v-model="dc.data.recipientId"/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-form-item label="送达方式" prop="deliveryMethodId">
|
||||||
|
<SimpleEntitySelector :disabled="dc.mode === 'detail'" @change="sdfsChange" :simpleConfig="simpleConfigSsr"
|
||||||
|
:multiple="false" v-model="dc.data.deliveryMethodId"/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-form-item label="实际送达时间" prop="deliveryTime">
|
||||||
|
<el-date-picker :disabled="dc.mode === 'detail'" v-model="dc.data.deliveryTime" 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="8"><el-form-item label="送达回证" prop="receiptProof"><el-input :disabled="dc.mode === 'detail'" v-model="dc.data.receiptProof"/></el-form-item></el-col>-->
|
||||||
|
<el-col :span="8" v-if="methodName === '电话送达'">
|
||||||
|
<el-form-item label="通话录音" prop="callTape">
|
||||||
|
<el-input :disabled="dc.mode === 'detail'" v-model="dc.data.callTape"/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8" v-if="methodName === '电子送达'">
|
||||||
|
<el-form-item label="送达类型" prop="deliveryType">
|
||||||
|
<el-select :disabled="dc.mode === 'detail'" v-model="dc.data.deliveryType" placeholder="请选择" clearable>
|
||||||
|
<el-option v-for="item in sdlxOptions" :key="item.value" :label="item.label"
|
||||||
|
:value="item.value"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8" v-if="methodName === '邮寄送达'">
|
||||||
|
<el-form-item label="快递单号" prop="trackingNo">
|
||||||
|
<el-input :disabled="dc.mode === 'detail'" v-model="dc.data.trackingNo"/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8" v-if="methodName === '邮寄送达'">
|
||||||
|
<el-form-item label="物流信息" prop="logistics.info">
|
||||||
|
<el-input :disabled="dc.mode === 'detail'" v-model="dc.data.logistics.info"/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8" v-if="methodName === '公告送达'">
|
||||||
|
<el-form-item label="刊登凭证" prop="appearedVoucher">
|
||||||
|
<el-input :disabled="dc.mode === 'detail'" v-model="dc.data.appearedVoucher"/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8" v-if="methodName === '委托送达' || methodName === '转交送达'">
|
||||||
|
<el-form-item label="委托人姓名" prop="trusteeName">
|
||||||
|
<el-input :disabled="dc.mode === 'detail'" v-model="dc.data.trusteeName"/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8" v-if="methodName !== '公告送达'">
|
||||||
|
<el-form-item label="状态" prop="status">
|
||||||
|
<el-radio-group v-model="dc.data.status" :disabled="dc.mode === 'detail'">
|
||||||
|
<el-radio :label="'0'" :value="'0'">正常送达</el-radio>
|
||||||
|
<el-radio :label="'1'" :value="'1'">留置送达</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="24" v-if="methodName">
|
||||||
|
<!-- v-if="methodName && (methodName === '直接送达' || methodName === '转交送达' || methodName === '留置送达')"-->
|
||||||
|
<el-form-item label="送达回证">
|
||||||
|
<MultiplePicture ref="multiple_pictures"
|
||||||
|
:form-data="{urls: dc.data.picList}"
|
||||||
|
:parameters="{mode: dc.mode, autoUpload: true, limit: 20}"
|
||||||
|
@on-success="onSuccess"
|
||||||
|
@on-pic-view="onPicView"
|
||||||
|
@on-remove="onRemove"/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item label="送达人电子签名" prop="recipientSignature">
|
||||||
|
<el-button type="primary" size="small" @click="openSignatureOne" v-if="dc.mode !== 'detail'">送达人电子签名
|
||||||
|
</el-button>
|
||||||
|
<div v-if="dc.data.recipientSignature"
|
||||||
|
style="border: 1px solid #ccc; margin-left: 10px; display: inline-block; position: relative;">
|
||||||
|
<img :src="dc.data.recipientSignature" alt="签名" style="height: 100px;"/>
|
||||||
|
<el-button v-if="dc.mode !== 'detail'" type="danger" size="small"
|
||||||
|
style="position: absolute; top: 5px; right: 5px; transform: translate(50%, -50%); border-radius: 50%; width: 20px; height: 20px; padding: 0;"
|
||||||
|
@click="saveSignatureOne('')">×
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item label="见证人电子签名" prop="witnessSignature">
|
||||||
|
<el-button type="primary" size="small" @click="openSignatureTwo" v-if="dc.mode !== 'detail'">见证人电子签名
|
||||||
|
</el-button>
|
||||||
|
<div v-if="dc.data.witnessSignature"
|
||||||
|
style="border: 1px solid #ccc; margin-left: 10px; display: inline-block; position: relative;">
|
||||||
|
<img :src="dc.data.witnessSignature" alt="签名" style="height: 100px;"/>
|
||||||
|
<el-button v-if="dc.mode !== 'detail'" type="danger" size="small"
|
||||||
|
style="position: absolute; top: 5px; right: 5px; transform: translate(50%, -50%); border-radius: 50%; width: 20px; height: 20px; padding: 0;"
|
||||||
|
@click="saveSignatureTwo('')">×
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<PictureView ref="pictureViewRef"/>
|
||||||
|
</el-row>
|
||||||
|
</template>
|
||||||
|
</browser>
|
||||||
|
<SignatureComponent v-model="showSignatureOne" @save="saveSignatureOne"/>
|
||||||
|
<SignatureComponent v-model="showSignatureTwo" @save="saveSignatureTwo"/>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import {reactive, toRefs, ref, watch, onMounted} from 'vue'
|
||||||
|
import Browser from '@/components/Browser.vue'
|
||||||
|
import {ElButton, ElMessage} from "element-plus"
|
||||||
|
import deliveryRecords from "@/api/lawenforcement/DeliveryRecord.js"
|
||||||
|
import SimpleEntitySelector from "@/components/SimpleEntitySelector.vue"
|
||||||
|
import MultiplePicture from "@pages/common/MultiplePicture.vue"
|
||||||
|
import PictureView from "@pages/common/PictureView.vue"
|
||||||
|
import SignatureComponent from "@pages/common/SignatureComponent.vue"
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
dialogData: {type: Object, default: () => ({})},
|
||||||
|
isNotDialog: {type: Boolean, default: true}
|
||||||
|
})
|
||||||
|
|
||||||
|
const state = reactive({
|
||||||
|
componentLoading: false,
|
||||||
|
permissions: {
|
||||||
|
query: props.isNotDialog,
|
||||||
|
add: props.isNotDialog,
|
||||||
|
modify: props.isNotDialog,
|
||||||
|
detail: true,
|
||||||
|
delete: props.isNotDialog,
|
||||||
|
deleteAll: props.isNotDialog,
|
||||||
|
importFile: false,
|
||||||
|
exportFile: false,
|
||||||
|
exportSelectFile: false,
|
||||||
|
downloadTemp: false,
|
||||||
|
},
|
||||||
|
tableConfig: {
|
||||||
|
tableData: {},
|
||||||
|
hasControlColumn: true,
|
||||||
|
controlWidth: props.isNotDialog ? '180' : '80',
|
||||||
|
multipleSelect: props.isNotDialog,
|
||||||
|
selectable: (row) => {
|
||||||
|
return row.deliveryMethod?.methodName === '电子送达' && row.deliveryType === '2'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
apiConfig: {
|
||||||
|
api: deliveryRecords,
|
||||||
|
modelId: 'deliveryId',
|
||||||
|
},
|
||||||
|
dialogConfig: {
|
||||||
|
show: false,
|
||||||
|
mode: 'detail',
|
||||||
|
formLabelWidth: '110px',
|
||||||
|
loading: false,
|
||||||
|
baseTitle: '执法文书送达',
|
||||||
|
rules: {
|
||||||
|
caseId: [{required: true, message: '案卷不能为空', trigger: 'change'}],
|
||||||
|
documentIds: [{required: true, message: '执法文书不能为空', trigger: 'change'}],
|
||||||
|
recipientId: [{required: true, message: '受送达人不能为空', trigger: 'change'}],
|
||||||
|
deliveryMethodId: [{required: true, message: '送达方式不能为空', trigger: 'change'}],
|
||||||
|
deliveryTime: [{required: false, message: '实际送达时间不能为空', trigger: 'change'}],
|
||||||
|
receiptProof: [{required: false, message: '送达回证不能为空', trigger: 'change'}, {
|
||||||
|
min: 0,
|
||||||
|
max: 255,
|
||||||
|
message: '送达回证的长度不能超过255',
|
||||||
|
trigger: 'change'
|
||||||
|
}],
|
||||||
|
callTape: [{required: false, message: '通话录音不能为空', trigger: 'change'}, {
|
||||||
|
min: 0,
|
||||||
|
max: 100,
|
||||||
|
message: '通话录音的长度不能超过100',
|
||||||
|
trigger: 'change'
|
||||||
|
}],
|
||||||
|
deliveryType: [{required: true, message: '送达类型不能为空', trigger: 'change'}],
|
||||||
|
trackingNo: [{required: false, message: '快递单号不能为空', trigger: 'change'}, {
|
||||||
|
min: 0,
|
||||||
|
max: 100,
|
||||||
|
message: '快递单号的长度不能超过100',
|
||||||
|
trigger: 'change'
|
||||||
|
}],
|
||||||
|
logistics: [{required: false, message: '物流信息不能为空', trigger: 'change'}],
|
||||||
|
appearedVoucher: [{required: false, message: '刊登凭证不能为空', trigger: 'change'}, {
|
||||||
|
min: 0,
|
||||||
|
max: 100,
|
||||||
|
message: '刊登凭证的长度不能超过100',
|
||||||
|
trigger: 'change'
|
||||||
|
}],
|
||||||
|
trusteeName: [{required: false, message: '委托人姓名不能为空', trigger: 'change'}, {
|
||||||
|
min: 0,
|
||||||
|
max: 20,
|
||||||
|
message: '委托人姓名的长度不能超过20',
|
||||||
|
trigger: 'change'
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
data: {},
|
||||||
|
actions: {
|
||||||
|
handleDialogOk: handleDialogOk
|
||||||
|
}
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
add: handleAdd,
|
||||||
|
modify: handleModify,
|
||||||
|
detail: handleDetail,
|
||||||
|
query: handleQuery,
|
||||||
|
handleSelectionChange
|
||||||
|
},
|
||||||
|
simpleConfigCase: {confName: 'case', parmas: {tag: 'Y'}},
|
||||||
|
simpleConfigZfws: {confName: 'document'},
|
||||||
|
simpleConfigSdfs: {confName: 'recipient'},
|
||||||
|
simpleConfigSsr: {confName: 'method'},
|
||||||
|
deliverys: [],
|
||||||
|
queryParams: {}
|
||||||
|
})
|
||||||
|
|
||||||
|
const {
|
||||||
|
componentLoading,
|
||||||
|
permissions,
|
||||||
|
tableConfig,
|
||||||
|
apiConfig,
|
||||||
|
dialogConfig,
|
||||||
|
actions,
|
||||||
|
simpleConfigCase,
|
||||||
|
simpleConfigZfws,
|
||||||
|
simpleConfigSdfs,
|
||||||
|
simpleConfigSsr,
|
||||||
|
deliverys,
|
||||||
|
queryParams
|
||||||
|
} = toRefs(state)
|
||||||
|
|
||||||
|
const sdlxOptions = reactive([{value: '1', label: '网站'}, {value: '2', label: '短信'}, {
|
||||||
|
value: '3',
|
||||||
|
label: '邮件'
|
||||||
|
}, {value: '4', label: '手机APP'}, {value: '5', label: '微信'}])
|
||||||
|
|
||||||
|
const methodName = ref('')
|
||||||
|
const caseId = ref('')
|
||||||
|
|
||||||
|
function sdfsChange(row) {
|
||||||
|
methodName.value = row?.methodName
|
||||||
|
if (methodName.value === '公告送达') {
|
||||||
|
dialogConfig.value.data.status = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function ajxxChange(row) {
|
||||||
|
caseId.value = row?.caseId
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleQuery() {
|
||||||
|
tableConfig.value.tableLoading = true
|
||||||
|
apiConfig.value.api.query(props.isNotDialog ? queryParams.value : props.dialogData).then(res => {
|
||||||
|
if (res.success) {
|
||||||
|
tableConfig.value.tableData = res
|
||||||
|
}
|
||||||
|
tableConfig.value.tableLoading = false
|
||||||
|
}).catch(() => tableConfig.value.tableLoading = false)
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleAdd() {
|
||||||
|
dialogConfig.value.show = true
|
||||||
|
methodName.value = null
|
||||||
|
dialogConfig.value.mode = 'add'
|
||||||
|
dialogConfig.value.title = '新增执法文书送达'
|
||||||
|
dialogConfig.value.data = Object.assign({}, {documentIds: [], materials: [], picList: [], logistics: {}, status: '0'})
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleModify(row) {
|
||||||
|
dialogConfig.value.show = true
|
||||||
|
methodName.value = null
|
||||||
|
dialogConfig.value.mode = 'modify'
|
||||||
|
dialogConfig.value.title = '修改执法文书送达'
|
||||||
|
dialogConfig.value.data.documentIds = []
|
||||||
|
findOne(row)
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDetail(row) {
|
||||||
|
dialogConfig.value.show = true
|
||||||
|
methodName.value = null
|
||||||
|
dialogConfig.value.mode = 'detail'
|
||||||
|
dialogConfig.value.title = '执法文书送达详情'
|
||||||
|
dialogConfig.value.showFooter = false
|
||||||
|
findOne(row)
|
||||||
|
}
|
||||||
|
|
||||||
|
function findOne(row) {
|
||||||
|
dialogConfig.value.loading = true
|
||||||
|
apiConfig.value.api.findOne(row[apiConfig.value.modelId]).then(res => {
|
||||||
|
if (res.success) {
|
||||||
|
dialogConfig.value.loading = false
|
||||||
|
let data = res.data
|
||||||
|
caseId.value = data.caseId
|
||||||
|
methodName.value = data.deliveryMethod?.methodName
|
||||||
|
data.logistics = data.logistics ? data.logistics : {}
|
||||||
|
data.documentIds = data.documentIds?.split(',') || []
|
||||||
|
if (data.materials) data.materials.forEach(item => item.uid = item.materialsId)
|
||||||
|
dialogConfig.value.data = Object.assign({}, data, {picList: data.materials})
|
||||||
|
} else {
|
||||||
|
dialogConfig.value.loading = false
|
||||||
|
throw new Error('查询失败')
|
||||||
|
}
|
||||||
|
}).catch(() => {
|
||||||
|
dialogConfig.value.loading = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDialogOk(formRef) {
|
||||||
|
let _event = actions.value
|
||||||
|
formRef.validate(valid => {
|
||||||
|
if (valid) {
|
||||||
|
dialogConfig.value.loading = true
|
||||||
|
let data = Object.assign({}, dialogConfig.value.data)
|
||||||
|
if (dialogConfig.value.mode === 'add') {
|
||||||
|
apiConfig.value.api.add(data).then(res => {
|
||||||
|
dialogConfig.value.show = false
|
||||||
|
if (res.success) {
|
||||||
|
ElMessage.success('操作成功')
|
||||||
|
_event.query()
|
||||||
|
} else {
|
||||||
|
throw new Error('操作失败')
|
||||||
|
}
|
||||||
|
dialogConfig.value.loading = false
|
||||||
|
}).catch(() => {
|
||||||
|
dialogConfig.value.loading = false
|
||||||
|
})
|
||||||
|
} else if (dialogConfig.value.mode === 'modify') {
|
||||||
|
apiConfig.value.api.modify(dialogConfig.value.data[apiConfig.value.modelId], data).then(res => {
|
||||||
|
dialogConfig.value.show = false
|
||||||
|
if (res.success) {
|
||||||
|
ElMessage.success('操作成功')
|
||||||
|
_event.query()
|
||||||
|
} else {
|
||||||
|
throw new Error('操作失败')
|
||||||
|
}
|
||||||
|
dialogConfig.value.loading = false
|
||||||
|
}).catch(() => {
|
||||||
|
dialogConfig.value.loading = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleSelectionChange(selectedData) {
|
||||||
|
deliverys.value = [...selectedData]
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleVoicePush(row) {
|
||||||
|
tableConfig.value.tableLoading = true
|
||||||
|
apiConfig.value.api.voicePush(row).then(res => {
|
||||||
|
if (res.success) {
|
||||||
|
ElMessage.success('操作成功')
|
||||||
|
} else {
|
||||||
|
throw new Error('操作失败')
|
||||||
|
}
|
||||||
|
tableConfig.value.tableLoading = false
|
||||||
|
}).catch(() => {
|
||||||
|
tableConfig.value.tableLoading = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleSms() {
|
||||||
|
let ids = deliverys.value.map((item) => item[apiConfig.value.modelId])
|
||||||
|
tableConfig.value.tableLoading = true
|
||||||
|
apiConfig.value.api.smsCall(ids).then(res => {
|
||||||
|
if (res.success) {
|
||||||
|
ElMessage.success('操作成功')
|
||||||
|
} else {
|
||||||
|
throw new Error('操作失败')
|
||||||
|
}
|
||||||
|
tableConfig.value.tableLoading = false
|
||||||
|
}).catch(() => {
|
||||||
|
tableConfig.value.tableLoading = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function onSuccess(data, file, row) {
|
||||||
|
let obj = {materialsId: file.uid, name: data.fileName, savePath: data.savePathName, url: data.url}
|
||||||
|
dialogConfig.value.data.materials.push(obj)
|
||||||
|
}
|
||||||
|
|
||||||
|
function onRemove(file, row) {
|
||||||
|
const idx = dialogConfig.value.data.materials.findIndex((item) => item.uid === file.uid)
|
||||||
|
if (idx > -1) dialogConfig.value.data.materials.splice(idx, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
const pictureViewRef = ref(null)
|
||||||
|
|
||||||
|
function onPicView(url) {
|
||||||
|
pictureViewRef.value.viewPicture(url)
|
||||||
|
}
|
||||||
|
|
||||||
|
const showSignatureOne = ref(false)
|
||||||
|
const openSignatureOne = () => {
|
||||||
|
showSignatureOne.value = true
|
||||||
|
}
|
||||||
|
const saveSignatureOne = (data) => {
|
||||||
|
dialogConfig.value.data.recipientSignature = data
|
||||||
|
}
|
||||||
|
const showSignatureTwo = ref(false)
|
||||||
|
const openSignatureTwo = () => {
|
||||||
|
showSignatureTwo.value = true
|
||||||
|
}
|
||||||
|
const saveSignatureTwo = (data) => {
|
||||||
|
dialogConfig.value.data.witnessSignature = data
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
Loading…
Reference in New Issue