tangweijie 5d43154ba5 feat: 新增问卷任务管理模块
- 新增问卷任务页面及组件(创建任务、人员选择、任务详情)
- 新增问卷预览组件
- 新增答题详情对话框
- 优化问卷列表和问卷记录页面
- 优化Dashboard风险趋势图Y轴动态缩放
- 更新评估报告导出页面
2026-01-24 10:56:02 +08:00

201 lines
5.8 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<el-dialog
v-model="dialogVisible"
title="选择犯人"
width="800px"
:close-on-click-modal="false"
>
<!-- 搜索区域 -->
<el-form :model="queryParams" :inline="true" class="mb-20px">
<el-form-item label="姓名">
<el-input v-model="queryParams.name" placeholder="请输入姓名" clearable style="width: 150px" />
</el-form-item>
<el-form-item label="编号">
<el-input v-model="queryParams.prisonerNo" placeholder="请输入编号" clearable style="width: 150px" />
</el-form-item>
<el-form-item label="监区">
<el-select v-model="queryParams.areaId" placeholder="请选择监区" clearable style="width: 150px">
<el-option v-for="item in areaList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleSearch"><Icon icon="ep:search" class="mr-5px" />搜索</el-button>
<el-button @click="handleReset"><Icon icon="ep:refresh" class="mr-5px" />重置</el-button>
</el-form-item>
</el-form>
<!-- 列表 -->
<el-table
ref="tableRef"
v-loading="loading"
:data="list"
@selection-change="handleSelectionChange"
:row-key="(row: any) => row.id"
>
<el-table-column type="selection" width="55" :reserve-selection="true" />
<el-table-column label="编号" align="center" prop="prisonerNo" width="100" />
<el-table-column label="姓名" align="center" prop="name" width="100" />
<el-table-column label="监区" align="center" prop="prisonAreaName" width="120" />
<el-table-column label="性别" align="center" prop="gender" width="80">
<template #default="scope">
{{ scope.row.gender === 1 ? '男' : '女' }}
</template>
</el-table-column>
<el-table-column label="入狱日期" align="center" prop="prisonDate" width="120">
<template #default="scope">
{{ formatDate(scope.row.prisonDate) }}
</template>
</el-table-column>
<el-table-column label="状态" align="center" prop="status" width="100">
<template #default="scope">
<el-tag :type="scope.row.status === 1 ? 'success' : 'info'" size="small">
{{ scope.row.status === 1 ? '在押' : '释放' }}
</el-tag>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<Pagination
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
<!-- 已选统计 -->
<div class="mt-20px">
<el-tag type="primary" size="large">已选择 {{ selectedList.length }} 人</el-tag>
<el-button v-if="selectedList.length > 0" type="warning" text @click="clearSelection" class="ml-10px">
清空选择
</el-button>
</div>
<template #footer>
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" :loading="loading" @click="handleConfirm">
确定(已选 {{ selectedList.length }} 人)
</el-button>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue'
import { formatDate } from '@/utils/formatTime'
import { PrisonerApi } from '@/api/prison/prisoner'
import { AreaApi } from '@/api/prison/area'
defineOptions({ name: 'PrisonerSelectorDialog' })
const emit = defineEmits(['confirm'])
const dialogVisible = ref(false)
const loading = ref(false)
const tableRef = ref()
const list = ref<any[]>([])
const total = ref(0)
const selectedList = ref<any[]>([])
const areaList = ref<any[]>([])
// 查询参数
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
name: '',
prisonerNo: '',
areaId: undefined as number | undefined,
status: 1 // 只查在押犯人
})
// 当前选中的ID列表用于回显
const currentSelectedIds = ref<number[]>([])
/** 打开弹窗 */
const open = (selectedIds: number[]) => {
dialogVisible.value = true
currentSelectedIds.value = [...selectedIds]
selectedList.value = []
queryParams.pageNo = 1
getList()
getAreas()
}
/** 获取列表 */
const getList = async () => {
loading.value = true
try {
const data = await PrisonerApi.getPrisonerPage(queryParams)
list.value = data.list || []
total.value = data.total
// 回显已选中的行
nextTick(() => {
currentSelectedIds.value.forEach(id => {
const row = list.value.find((item: any) => item.id === id)
if (row) {
tableRef.value?.toggleRowSelection(row, true)
}
})
})
} finally {
loading.value = false
}
}
/** 获取监区列表 */
const getAreas = async () => {
try {
const data = await AreaApi.getAreaTree({})
// 提取所有监区用于下拉选择
const extractAreas = (nodes: any[]): any[] => {
const result: any[] = []
nodes.forEach(node => {
result.push({ id: node.id, name: node.name })
if (node.children && node.children.length > 0) {
result.push(...extractAreas(node.children))
}
})
return result
}
areaList.value = extractAreas(data || [])
} catch (e) {
console.error('获取监区列表失败', e)
}
}
/** 搜索 */
const handleSearch = () => {
queryParams.pageNo = 1
getList()
}
/** 重置 */
const handleReset = () => {
queryParams.name = ''
queryParams.prisonerNo = ''
queryParams.areaId = undefined
handleSearch()
}
/** 选择变化 */
const handleSelectionChange = (rows: any[]) => {
selectedList.value = rows
}
/** 清空选择 */
const clearSelection = () => {
selectedList.value = []
tableRef.value?.clearSelection()
}
/** 确认选择 */
const handleConfirm = () => {
const ids = selectedList.value.map(row => row.id)
emit('confirm', ids)
dialogVisible.value = false
}
defineExpose({ open })
</script>