Browse Source

20250328

main
wxc 10 months ago
parent
commit
deafd43ec8
  1. 3
      index.html
  2. 3
      package.json
  3. 1
      public/decoder.js
  4. BIN
      public/decoder.wasm
  5. 1
      public/jessibuca.js
  6. 1
      public/js/liveplayer-lib.min.js
  7. 6
      src/App.vue
  8. 7
      src/api/books.ts
  9. 6
      src/api/data/caseVerif.ts
  10. 8
      src/api/data/mailbox.ts
  11. 7
      src/api/data/petition12337.ts
  12. 37
      src/api/data/supervisionNotify.ts
  13. 6
      src/api/data/videoInspection.ts
  14. 9
      src/api/rightsComfort/comfort.ts
  15. 23
      src/api/rightsComfort/comfortPacks.ts
  16. 2
      src/api/screen/jwpy.ts
  17. 8
      src/api/system/depart.ts
  18. 30
      src/api/system/handleResultMaping.ts
  19. 48
      src/api/system/videoConfig.ts
  20. 15
      src/api/work/myCountersign.ts
  21. 7
      src/api/work/negativeTask.ts
  22. 151
      src/components/comfort/dialog.vue
  23. 10
      src/components/data/gj-import.vue
  24. 2
      src/components/datav/date-picker.vue
  25. 10
      src/components/datav/message.vue
  26. 3
      src/components/datav/statistic.vue
  27. 10
      src/components/datav/tab-item.vue
  28. 85
      src/components/datav/tabs.vue
  29. 2
      src/components/file/list.vue
  30. 421
      src/components/file/preview.vue
  31. 5
      src/components/file/upload.vue
  32. 34
      src/components/home/work/index.vue
  33. 105
      src/components/home/work/my-comfort.vue
  34. 8
      src/components/negative/action-history.vue
  35. 161
      src/components/negative/add.vue
  36. 2
      src/components/negative/apply-completion.vue
  37. 2
      src/components/negative/apply-countersign.vue
  38. 5
      src/components/negative/apply-extension.vue
  39. 26
      src/components/negative/description.vue
  40. 80
      src/components/negative/dialog.vue
  41. 27
      src/components/negative/verify-description.vue
  42. 74
      src/components/negative/verify.vue
  43. 1
      src/components/negativeInfo/depart-dialog.vue
  44. 7
      src/components/query-select.vue
  45. 60
      src/components/video-play.vue
  46. 20
      src/layout/components/Aside.vue
  47. 4
      src/router/routes.ts
  48. 59
      src/style/public.scss
  49. 4
      src/utils/feedback.ts
  50. 347
      src/views/books/Audit.vue
  51. 3
      src/views/books/Gabxf.vue
  52. 185
      src/views/books/Mail12337.vue
  53. 91
      src/views/data/Ajhc.vue
  54. 49
      src/views/data/Gabxf.vue
  55. 46
      src/views/data/Gjxf.vue
  56. 129
      src/views/data/ImportRecords.vue
  57. 6
      src/views/data/Mail12337.vue
  58. 196
      src/views/data/Mailbox.vue
  59. 376
      src/views/data/VideoInspection.vue
  60. 288
      src/views/datav/AuditSuper.vue
  61. 48
      src/views/datav/CaseVerif.vue
  62. 4
      src/views/datav/Jwpy.vue
  63. 1244
      src/views/datav/SceneInsp.vue
  64. 71
      src/views/datav/VideoInsp.vue
  65. 2
      src/views/datav/subonedatav/SubOneAuditSuper.vue
  66. 2
      src/views/datav/subonedatav/SubOneCaseVerif.vue
  67. 3
      src/views/datav/subonedatav/SubOneMailVisits.vue
  68. 10
      src/views/datav/subonedatav/SubOneSceneInsp.vue
  69. 436
      src/views/datav/subonedatav/SubOneVideoInsp.vue
  70. 13
      src/views/rightsComfort/Comfort.vue
  71. 445
      src/views/rightsComfort/ComfortPacks.vue
  72. 492
      src/views/rightsComfort/MyComfort.vue
  73. 82
      src/views/rightsComfort/Rights.vue
  74. 4
      src/views/sensitivePerception/Model.vue
  75. 28
      src/views/sensitivePerception/ModelClue.vue
  76. 29
      src/views/sensitivePerception/ModelClueManual.vue
  77. 2
      src/views/sensitivePerception/ModelClueTask.vue
  78. 251
      src/views/system/HandleResultMaping.vue
  79. 46
      src/views/system/Menu.vue
  80. 105
      src/views/system/Police.vue
  81. 295
      src/views/system/VideoConfig.vue
  82. 1
      src/views/system/Wqzg.vue
  83. 29
      src/views/work/Alarm.vue
  84. 26
      src/views/work/BatchDistribute.vue
  85. 3
      src/views/work/Done.vue
  86. 528
      src/views/work/MyCountersign.vue
  87. 14
      src/views/work/NegativeImport.vue
  88. 6
      src/views/work/NegativeTask.vue
  89. 141
      src/views/work/News.vue
  90. 86
      src/views/work/Query.vue
  91. 56
      src/views/work/Todo.vue
  92. 1813
      src/views/work/VerifySubmit.vue

3
index.html

@ -15,5 +15,8 @@
<script type="module" src="/src/main.ts"></script>
<script src="/js/authen.js"></script>
<script src="/js/pnxclient.js"></script>
<!-- 视频 -->
<script src="/js/liveplayer-lib.min.js"></script>
<script src="/jessibuca.js"></script>
</body>
</html>

3
package.json

@ -15,6 +15,7 @@
},
"dependencies": {
"@element-plus/icons-vue": "^2.3.1",
"@liveqing/liveplayer-v3": "^3.7.35",
"@univerjs/core": "^0.2.5",
"@univerjs/data-validation": "^0.2.5",
"@univerjs/design": "^0.2.5",
@ -37,7 +38,7 @@
"echarts": "^5.4.3",
"element-plus": "^2.8.8",
"flv.js": "^1.6.2",
"hls.js": "^1.5.18",
"hls.js": "^1.5.20",
"install": "^0.13.0",
"lodash": "^4.17.21",
"moment": "^2.30.1",

1
public/decoder.js

File diff suppressed because one or more lines are too long

BIN
public/decoder.wasm

Binary file not shown.

1
public/jessibuca.js

File diff suppressed because one or more lines are too long

1
public/js/liveplayer-lib.min.js vendored

File diff suppressed because one or more lines are too long

6
src/App.vue

@ -4,11 +4,11 @@
</el-config-provider>
</template>
<script setup>
import zhCn from 'element-plus/es/locale/lang/zh-cn'
import zhCn from "element-plus/es/locale/lang/zh-cn";
const elConfig = {
zIndex: 3000,
locale: zhCn
}
locale: zhCn,
};
</script>

7
src/api/books.ts

@ -29,3 +29,10 @@ export function listNegativeAjhc(query) {
query
});
}
export function listNegativeAudit(query) {
return request.get({
url: `/negative/books/audit`,
query
});
}

6
src/api/data/caseVerif.ts

@ -33,3 +33,9 @@ export function distributeCaseVerif(body) {
body
});
}
export function getNegativeId(originId) {
return request.get({
url: '/data/caseVerif/getNegativeId?originId=' + originId
});
}

8
src/api/data/mailbox.ts

@ -0,0 +1,8 @@
import request from "@/api/request";
export function listMailbox(query) {
return request.get({
url: '/data/mailbox',
query
});
}

7
src/api/data/petition12337.ts

@ -26,3 +26,10 @@ export function distributePetitionComplaint12337(body) {
body
});
}
export function listPetitionComplaint12337Books(query) {
return request.get({
url: '/negative/books/mail12337',
query
});
}

37
src/api/data/supervisionNotify.ts

@ -50,45 +50,12 @@ export function getSupervisionNotifyMap(times) {
/**
*
*/
export function getYellowBetDrug(times) {
export function getYellowBetDrug(times, dictValue) {
return request.get({
url: `/datav/supervisonNotify/getYellowBetDrug?beginTime=${times[0]}&endTime=${times[1]}`
url: `/datav/supervisonNotify/getYellowBetDrug?beginTime=${times[0]}&endTime=${times[1]}&dictValue=${dictValue}`
});
}
// 枪支管理数据
export function getGunController(times) {
return request.get({
url: `/datav/supervisonNotify/getGunController?beginTime=${times[0]}&endTime=${times[1]}`
});
}
// 枪支管理数据
export function getCompanyProblem(times) {
return request.get({
url: `/datav/supervisonNotify/getCompanyProblem?beginTime=${times[0]}&endTime=${times[1]}`
});
}
// 执法办案数据
export function getHandleCase(times) {
return request.get({
url: `/datav/supervisonNotify/getHandleCase?beginTime=${times[0]}&endTime=${times[1]}`
});
}
// 枪支管理数据
export function getCheckBeer(times) {
return request.get({
url: `/datav/supervisonNotify/getCheckBeer?beginTime=${times[0]}&endTime=${times[1]}`
});
}
export function getWorkDynamics(times) {
return request.get({
url: `/datav/supervisonNotify/getWorkDynamics?beginTime=${times[0]}&endTime=${times[1]}`

6
src/api/data/videoInspection.ts

@ -19,3 +19,9 @@ export function distributeData(body) {
body
});
}
export function updateState(id, state) {
return request.put({
url: `/videoInspection/state/${id}?state=${state}`
});
}

9
src/api/rightsComfort/comfort.ts

@ -8,7 +8,7 @@ export function listComfort(query) {
});
}
export function listTodos(query) {
export function listComfortTodos(query) {
return request.get({
url: `/comfort/todo`,
query: query
@ -35,6 +35,13 @@ export function applyComfort(body) {
});
}
export function updateComfort(body) {
return request.put({
url: `/comfort`,
body
});
}
export function delComfort(id) {
return request.del({
url: `/comfort/` + id

23
src/api/rightsComfort/comfortPacks.ts

@ -0,0 +1,23 @@
import request from "@/api/request";
export function listComfortPacks(query) {
return request.get({
url: `/comfort/packs`,
query
});
}
export function getComfortPacks(id) {
return request.get({
url: `/comfort/packs/${id}`
});
}
export function addComfortPacks(body) {
return request.post({
url: `/comfort/packs`,
body
});
}

2
src/api/screen/jwpy.ts

@ -31,7 +31,7 @@ export function GetZHMYLPM(PeriodId, PeriodSonID, OrgId, TaskID, TaskClass) {
formData.append("PeriodSonID", PeriodSonID);
OrgId && formData.append("OrgId", OrgId);
TaskID && formData.append("TaskID", TaskID);
TaskID && TaskClass && formData.append("TaskClass", TaskClass);
formData.append("TaskClass", 1);
return outrequest.post({
url: `/out-police-service/api/DSJ/GetZHMYLPM`,
body: formData

8
src/api/system/depart.ts

@ -58,9 +58,15 @@ export function updateDepart(body) {
});
}
export function delDepart(id) {
return request.del({
url: `/depart/${id}`
});
}
// 获取分县市局树结构
export function getCountyAndCityBureausTree() {
return request.get({
url: `/depart/tree/countyAndCityBureaus`
});
}

30
src/api/system/handleResultMaping.ts

@ -0,0 +1,30 @@
import request from "@/api/request";
export function listHandleResultMaping(query) {
return request.get({
url: '/handleResultMaping',
query
});
}
export function addHandleResultMaping(body) {
return request.post({
url: '/handleResultMaping',
body
});
}
export function updateHandleResultMaping(body) {
return request.put({
url: '/handleResultMaping',
body
});
}
export function delHandleResultMaping(id) {
return request.del({
url: '/handleResultMaping/' + id
});
}

48
src/api/system/videoConfig.ts

@ -0,0 +1,48 @@
import request from "@/api/request";
export function listVideoConfig(query) {
return request.get({
url: '/videoConfig',
query
});
}
export function getVideoWsUrl() {
return request.get({
url: '/videoConfig/getVideoWsUrl'
});
}
export function addVideoConfig(body) {
return request.post({
url: '/videoConfig',
body
});
}
export function updateVideoConfig(body) {
return request.put({
url: '/videoConfig',
body
});
}
export function delVideoConfig(id) {
return request.del({
url: '/videoConfig/' + id
});
}
export function listDevice(query) {
return request.get({
url: '/videoConfig/device',
query
});
}
export function listVideoConfigByDepartId(departId) {
return request.get({
url: '/videoConfig/depart/' + departId
});
}

15
src/api/work/myCountersign.ts

@ -0,0 +1,15 @@
import request from "@/api/request";
export function listMyCountersign(query) {
return request.get({
url: `/work/countersign`,
query
});
}
export function negativeExport(query) {
return request.post({
url: `/work/countersign/export/excel`,
query
});
}

7
src/api/work/negativeTask.ts

@ -7,13 +7,6 @@ export function listNegativeTask(query) {
});
}
export function listNegativeTaskImport(query) {
return request.get({
url: `/negativeTask/importList`,
query
});
}
export function importNegative(body) {
return request.post({
url: `/negativeTask/import`,

151
src/components/comfort/dialog.vue

@ -16,60 +16,76 @@
<div class="col col-6">
<label>性别</label>
<span>
<span v-if="comfort.person.sex === 0"></span>
<span v-if="comfort.person.sex === 1"></span>
<span v-if="comfort.person?.sex === 0"></span>
<span v-if="comfort.person?.sex === 1"></span>
</span>
</div>
<div class="col col-6">
<label>出生年月</label>
<span>{{ comfort.person.birthday }}</span>
<span>{{ comfort.person?.birthday }}</span>
</div>
<div class="col col-6">
<label>文化程度</label>
<span>{{ comfort.person.levelEducation }}</span>
<span>{{ comfort.person?.levelEducation }}</span>
</div>
<div class="col col-6">
<label>政治面貌</label>
<span>{{ comfort.person.politicCountenance }}</span>
<span>{{ comfort.person?.politicCountenance }}</span>
</div>
<div class="col col-6">
<label>身份证号码</label>
<span>{{ comfort.person.idCode }}</span>
<span>{{ comfort.person?.idCode }}</span>
</div>
<div class="col col-6">
<label>联系电话</label>
<span>{{ comfort.person.mobile }}</span>
<span>{{ comfort.person?.mobile }}</span>
</div>
<div class="col col-6">
<label>单位</label>
<span>{{ comfort.person.departName }}</span>
<span>{{ comfort.person?.departName }}</span>
</div>
<div class="col col-6">
<label>职务</label>
<span>{{ comfort.person.job }}</span>
<span>{{ comfort.person?.job }}</span>
</div>
<div class="col col-6">
<label>警号</label>
<span>{{ comfort.person.empNo }}</span>
<span>{{ comfort.person?.empNo }}</span>
</div>
<div class="col col-6">
<label>警衔</label>
<span>{{ comfort.person.policeRank }}</span>
<span>{{ comfort.person?.policeRank }}</span>
</div>
<div class="col col-6">
<label>开户行</label>
<span>{{ comfort.person.bankCard }}</span>
<span>{{ comfort.person?.bankCard }}</span>
</div>
<div class="col col-6">
<label>所属支行</label>
<span>{{ comfort.person.bankBranch }}</span>
<span>{{ comfort.person?.bankBranch }}</span>
</div>
<div class="col col-6">
<label>银行账号</label>
<span>{{ comfort.person.bankCardAccount }}</span>
<span>{{ comfort.person?.bankCardAccount }}</span>
</div>
</div>
<el-divider />
<template v-if="comfort.apply.isSelf === '0'">
<div class="row">
<div class="col col-6">
<label>代理人关系</label>
<span>{{
comfort.apply.relation === "1" ? "同事" : "亲属"
}}</span>
</div>
<div class="col col-6">
<label>代理人姓名</label>
<span>{{ comfort.apply.agentName }}</span>
</div>
</div>
<el-divider />
</template>
<h3>案发情况</h3>
<div class="row">
<div class="col col-6">
@ -82,7 +98,7 @@
</div>
<div class="col col-6">
<label>受伤程度</label>
<span>{{ comfort.applyPerson.injurySeverity }}</span>
<span>{{ comfort.applyPerson.injurySeverityName }}</span>
</div>
<div class="col col-6">
<label>办案单位</label>
@ -109,7 +125,7 @@
<h3>佐证材料</h3>
<div>
<template v-if="comfort.apply.documentFile">
<file-todos
<file-list
:files="JSON.parse(comfort.apply.documentFile)"
/>
</template>
@ -123,42 +139,14 @@
<el-divider />
<h3>审批流程</h3>
<div class="comments-container flex gap-20">
<div class="item">
<div class="item" v-for="item in comfort.approves" :key="item">
<div class="flex center mb-20 relative comments-header">
<icon
name="el-icon-CircleCheck"
:size="41"
color="var(--primary-color)"
/>
</div>
<h1 class="text-center mb-16">
<span class="text-primary">申请抚慰</span>
</h1>
<h2 class="text-center mb-20">
{{ comfort.apply.applicantEmpName }}
</h2>
<div style="padding: 8px">
<h4 class="text-right">
{{ comfort.apply.applyDate }}
</h4>
</div>
</div>
<div class="item">
<div class="flex center mb-20 relative comments-header">
<template
v-if="
comfort.approves.find((item) => item.step === 2)
"
>
<template v-if="item.returnFlag !== null">
<icon
name="local-icon-return"
:size="41"
color="#FF0606"
v-if="
comfort.approves.find(
(item) => item.step === 2
).returnFlag
"
v-if="item.returnFlag"
/>
<icon
name="el-icon-CircleCheck"
@ -170,51 +158,29 @@
<div class="icon" v-else></div>
</div>
<h1 class="text-center mb-16">
<span>待审批</span>
</h1>
<h2 class="text-center mb-20">
维权专干 {{ comfort.apply.approver }}
</h2>
<div style="padding: 8px">
<h3>{{}}</h3>
<p style="font-weight: 700">{{}}</p>
<h4 class="text-right">{{}}</h4>
</div>
</div>
<div class="item">
<div class="flex center mb-20 relative comments-header">
<template
v-if="
comfort.approves.find((item) => item.step === 2)
<span
:class="
item.returnFlag === null
? ''
: item.returnFlag
? 'text-danger'
: 'text-primary'
"
>{{ item.actionName }}</span
>
<icon
name="local-icon-return"
:size="41"
color="#FF0606"
v-if="
comfort.approves.find(
(item) => item.step === 2
).returnFlag
"
/>
<icon
name="el-icon-CircleCheck"
:size="41"
color="var(--primary-color)"
v-else
/>
</template>
<div class="icon" v-else></div>
</div>
<h1 class="text-center mb-16">
<span>待审批</span>
</h1>
<h2 class="text-center mb-20">市局 维权专干</h2>
<h2 class="text-center mb-20">{{ item.handleName }}</h2>
<div style="padding: 8px">
<h3>{{}}</h3>
<p style="font-weight: 700">{{}}</p>
<h4 class="text-right">{{}}</h4>
<h4>
{{ item.createTime }}
</h4>
<h3>
<span>{{ item.commentLabel }}</span>
</h3>
<p style="font-weight: 700">
{{ item.comments }}
</p>
</div>
</div>
</div>
@ -238,7 +204,7 @@
<el-form
label-position="top"
ref="formRef"
:model="form"
:model="formData"
style="height: 400px"
>
<el-form-item
@ -337,10 +303,10 @@ async function submit() {
returnFlag: formData.value.returnFlag,
comments: formData.value.comments,
});
approveShow.value = false
approveShow.value = false;
formData.value = {};
feedback.msgSuccess("操作成功");
dialogShow.value = false
dialogShow.value = false;
emit("update");
}
</script>
@ -356,7 +322,7 @@ async function submit() {
content: "";
position: absolute;
top: 50%;
right: calc(50% + 30px);
right: calc(50% + 25px);
width: calc(100% - 30px);
border-top: 2px solid var(--second-color);
}
@ -388,6 +354,7 @@ async function submit() {
font-size: 12px;
color: #666;
font-weight: 500;
margin-top: 0;
}
p {
color: #333;

10
src/components/data/gj-import.vue

@ -152,6 +152,14 @@
title="导入成功"
:sub-title="` 已成功导入${importTableData.length}条数据。`"
>
<template #sub-title>
<p>已成功导入{{ importTableData.length }}条数据您可通过<span
class="link pointer"
@click="router.push('/data/ImportRecords')"
>导入记录</span
>功能查看导入记录
</p>
</template>
</el-result>
</template>
</div>
@ -243,6 +251,8 @@ watch(
}
}
);
const router = useRouter();
</script>
<style lang="scss" scoped>
</style>

2
src/components/datav/date-picker.vue

@ -17,7 +17,7 @@
</div>
</template>
<script setup>
import moment from 'moment'
const props = defineProps({
modelValue: {

10
src/components/datav/message.vue

@ -3,7 +3,10 @@
<div class="message" :type="type">
<div class="message-title">{{ title }}</div>
<div class="message-content">{{ content }}</div>
<div class="message-footer flex end">
<div class="message-footer flex between v-center">
<div>
<slot name="link"></slot>
</div>
<span>{{ date }}</span>
</div>
</div>
@ -26,6 +29,10 @@ const props = defineProps( {
date: {
type: String,
required: true
},
files: {
type: Array,
default: []
}
})
@ -57,4 +64,5 @@ const messageClass = computed(() => `message ${props.type}`);
margin-bottom: 10px;
}
}
</style>

3
src/components/datav/statistic.vue

@ -22,10 +22,11 @@ const props = defineProps({
},
//
isDecimal: {
type: String,
type: Boolean,
default: false
}
});
const value = ref(props.value);
watch(() => props.value, (val) => {
value.value = val;

10
src/components/datav/tab-item.vue

@ -4,7 +4,9 @@
</div>
</template>
<script setup>
defineProps({
import { onMounted } from "vue";
const props = defineProps({
label: {
type: String,
},
@ -13,6 +15,12 @@ defineProps({
},
});
const activeTab = inject("activeTab");
const registerTab = inject('registerTab');
onMounted(() => {
registerTab({ name: props.name, label: props.label });
})
</script>
<style lang="scss" scoped>

85
src/components/datav/tabs.vue

@ -4,13 +4,12 @@
<div class="tab-header flex mb-20" v-if="type === ''" :size="size">
<div
class="tab-title-item"
v-for="item in slots"
:key="item.props.name"
:active="item.props.name === activeTab"
@click="handleChangeActiveTab(item.props.name)"
v-for="item in tabs"
:key="item.name"
:active="item.name === activeTab"
@click="handleChangeActiveTab(item)"
>
{{ item.props.label }}
{{ item.label }}
</div>
</div>
</el-scrollbar>
@ -23,17 +22,19 @@
>
<div
class="tab-title-item"
v-for="item in slots"
:key="item.props.name"
:active="item.props.name === activeTab"
@click="handleChangeActiveTab(item.props.name)"
v-for="item in tabs"
:key="item.name"
:active="item.name === activeTab"
@click="handleChangeActiveTab(item)"
>
{{ item.props.label }}
{{ item.label }}
</div>
</div>
</div>
</template>
<script setup>
import { computed } from "vue";
const props = defineProps({
modelValue: {
type: String,
@ -45,33 +46,51 @@ const props = defineProps({
},
size: {
type: String,
default: ""
}
default: "",
},
});
const slots = useSlots().default();
const emit = defineEmits(["update:modelValue"]);
const activeTab = ref(props.modelValue || slots[0].props.name);
watch(() => props.modelValue, () => {
activeTab.value = props.modelValue
})
watch(activeTab, (val) => {
emit("update:modelValue", val);
})
const tabs = ref([]);
const activeTab = ref(props.modelValue);
const registerTab = (tab) => {
if (!tabs.value.some((t) => t.name === tab.name)) {
tabs.value.push(tab);
if (!activeTab.value) {
activeTab.value = tab.name
}
}
};
provide("registerTab", registerTab);
provide("activeTab", activeTab);
watch(
() => props.modelValue,
() => {
activeTab.value = props.modelValue;
}
);
watch(activeTab, (val) => {
emit("update:modelValue", val);
});
function handleChangeActiveTab(name) {
activeTab.value = name;
emit("update:modelValue", name);
function handleChangeActiveTab(item) {
activeTab.value = item.name;
emit("update:modelValue", item.name);
}
</script>
<style lang="scss" scoped>
.tab-header {
width: max-content;
gap: 20px;
> * {
margin-right: 20px;
&:last-child {
margin-right: 0;
}
}
.tab-title-item {
font-size: 22px;
line-height: 34px;
@ -80,16 +99,19 @@ function handleChangeActiveTab(name) {
cursor: pointer;
&[active="true"] {
color: #fff;
border-color: #28E6FF;
border-color: #28e6ff;
}
}
&[size="small"] {
> * {
margin-right: 12px;
&:last-child {
margin-right: 0;
}
}
&[size=small] {
gap: 12px;
.tab-title-item {
font-size: 19px;
}
}
}
.tab-title {
@ -116,6 +138,5 @@ function handleChangeActiveTab(name) {
border-radius: 103px; /* 当只有唯一一个元素时,设置所有四个角的圆角 */
}
}
}
</style>

2
src/components/file/list.vue

@ -429,7 +429,7 @@ function rotateRight() {
.img-container {
img {
max-height: 100%;
max-height: 100vh;
&:hover {
cursor: pointer;
}

421
src/components/file/preview.vue

@ -0,0 +1,421 @@
<template>
<div class="file-preview-wrapper flex overlay" v-if="preview">
<el-scrollbar height="100vh">
<div class="file-list">
<section
v-for="(item, index) in files"
:key="index"
class="flex gap v-center pointer"
:active="files.indexOf(activeFile) === index"
@click="filePreview(item)"
>
<icon :name="getIconName(item.fileName)" :size="24" />
<span>{{ item.fileName }}</span>
</section>
</div>
</el-scrollbar>
<div class="file-content flex center v-center" @click="preview = false">
<div
class="img-container flex center"
v-if="getFileType(activeFile.fileName) === FileType.IMG"
@wheel="wheel"
>
<img
:src="`${BASE_PATH}/file/stream/${activeFile.filePath}`"
ref="imgRef"
@click.stop
:style="{
transform: `rotate(${rotate}deg) scale(${scale}) translate(${translateX}px, ${translateY}px)`,
}"
@mousedown="mousedown"
@mousemove="mousemove"
@mouseup="mouseup"
draggable="false"
/>
<button
class="rotate-left-btn pointer"
@click.stop.prevent="rotateLeft"
size="small"
title="左旋转"
>
<icon name="local-icon-rotate-left" :size="28" />
</button>
<button
class="rotate-right-btn pointer"
@click.stop.prevent="rotateRight"
size="small"
title="右旋转"
>
<icon name="local-icon-rotate-right" :size="28" />
</button>
</div>
<template
v-else-if="getFileType(activeFile.fileName) === FileType.PDF"
>
<iframe
:src="`${BASE_PATH}/file/stream/${activeFile.filePath}`"
style="height: 100vh; width: 900px"
></iframe>
</template>
<template
v-else-if="getFileType(activeFile.fileName) === FileType.MP3"
>
<audio controls style="width: 50vw">
<source
:src="`${BASE_PATH}/file/stream/${activeFile.filePath}`"
type="audio/mp3"
/>
</audio>
</template>
<template
v-else-if="getFileType(activeFile.fileName) === FileType.MP4"
>
<video controls @click.stop style="max-height: 100vh">
<source
:src="`${BASE_PATH}/file/stream/${activeFile.filePath}`"
type="video/mp4"
/>
</video>
</template>
<template
v-else-if="getFileType(activeFile.fileName) === FileType.WORD"
>
<vue-office-docx
:src="`${BASE_PATH}/file/stream/${activeFile.filePath}`"
style="height: 100vh; width: 900px"
@error="fileRrror = true"
v-if="!fileRrror"
@click.stop
/>
<div v-else class="error flex column text-center">
<span style="padding: 20px"
>文件预览解析错误如有需要请下载到本地预览</span
>
</div>
</template>
<template
v-else-if="
getFileType(activeFile.fileName) === FileType.EXCEL &&
activeFile.fileName.toLocaleLowerCase().endsWith('.xlsx')
"
>
<vue-office-excel
:src="`${BASE_PATH}/file/stream/${activeFile.filePath}`"
style="height: 100vh; width: 60vw"
@error="fileRrror = true"
v-if="!fileRrror"
@click.stop
/>
<div v-else class="error flex column text-center">
<span style="padding: 20px"
>文件预览解析错误如有需要请下载到本地预览</span
>
</div>
</template>
<template v-else>
<div style="background: #fff">
<el-result
icon="error"
title="不支持预览"
sub-title="该文件格式暂不支持预览,请下载预览"
style="background: #fff; width: 600px; height: 400px"
@click.stop
>
<template #extra>
<el-button
type="primary"
text
size="large"
@click="download"
>下载文件</el-button
>
</template>
</el-result>
</div>
</template>
<div class="file-number" @click.stop>
<span
>{{ files.indexOf(activeFile) + 1 }} /
{{ files.length }}</span
>
</div>
<button
class="left-btn pointer"
@click.stop.prevent="prev"
v-if="files.length > 1"
>
<icon name="el-icon-ArrowLeftBold" :size="28" />
</button>
<button
class="right-btn pointer"
@click.stop.prevent="next"
v-if="files.length > 1"
>
<icon name="el-icon-ArrowRightBold" :size="28" />
</button>
</div>
<div class="close-btn"></div>
<button class="close-btn pointer" @click="preview = false">
<icon name="el-icon-Close" :size="28" />
</button>
<el-button class="download-btn" @click="download" type="primary" plain>
<template #icon>
<icon name="el-icon-Download" :size="20" />
</template>
下载文件
</el-button>
</div>
</template>
<script setup>
import { BASE_PATH } from "@/api/request";
import { FileType } from "@/enums/fileEnums";
import { getFileType, getIconName } from "@/utils/util";
import "@vue-office/docx/lib/index.css";
import "@vue-office/excel/lib/index.css";
import VueOfficeDocx from "@vue-office/docx";
import VueOfficeExcel from "@vue-office/excel";
const props = defineProps({
files: {
type: Array,
default: () => [],
},
show: {
type: Boolean,
default: false,
},
});
const emit = defineEmits(["update:show"]);
const preview = ref(false);
const activeFile = ref({});
watch(
() => props.show,
(val) => {
preview.value = val;
nextTick(() => {
if (
val &&
Object.keys(activeFile.value).length === 0 &&
props.files.length > 0
) {
activeFile.value = props.files[0];
rotate.value = 0;
scale.value = 1;
translateX.value = 0;
translateY.value = 0;
moveFlag = false;
}
});
}
);
watch(preview, (val) => {
emit("update:show", val);
});
const rotate = ref(0);
const scale = ref(0);
const translateX = ref(0);
const translateY = ref(0);
let moveFlag = false;
let initialX = 0;
let initialY = 0;
const fileRrror = ref(false);
function filePreview(file) {
preview.value = true;
activeFile.value = file;
rotate.value = 0;
scale.value = 1;
translateX.value = 0;
translateY.value = 0;
moveFlag = false;
}
function download() {
window.open(`${BASE_PATH}/file/stream/${activeFile.value.filePath}`);
}
function prev() {
const index = props.files.indexOf(activeFile.value);
if (index === 0) {
filePreview(props.files[props.files.length - 1]);
} else {
filePreview(props.files[index - 1]);
}
}
function next() {
const index = props.files.indexOf(activeFile.value);
if (index === props.files.length - 1) {
filePreview(props.files[0]);
} else {
filePreview(props.files[index + 1]);
}
}
function wheel(event) {
if (event.deltaY > 0 && scale.value > 0.5) {
scale.value -= 0.1;
}
if (event.deltaY < 0) {
scale.value += 0.1;
}
}
function mousedown() {
moveFlag = true;
initialX = event.clientX;
initialY = event.clientY;
}
function mousemove(event) {
if (!moveFlag) {
return;
}
if (rotate.value % 360 === 0) {
translateX.value += event.clientX - initialX;
translateY.value += event.clientY - initialY;
}
if (rotate.value === 90) {
translateY.value -= event.clientX - initialX;
translateX.value += event.clientY - initialY;
}
if (rotate.value === 180) {
translateX.value -= event.clientX - initialX;
translateY.value -= event.clientY - initialY;
}
if (rotate.value === 270) {
translateY.value += event.clientX - initialX;
translateX.value -= event.clientY - initialY;
}
initialX = event.clientX;
initialY = event.clientY;
}
function mouseup(event) {
moveFlag = false;
}
function rotateLeft() {
if (rotate.value === 360) {
rotate.value = 0;
} else {
rotate.value += 90;
}
}
function rotateRight() {
if (rotate.value === 0) {
rotate.value = 270;
} else {
rotate.value -= 90;
}
}
</script>
<style lang="scss" scoped>
.file-preview-wrapper {
.file-list {
width: 15vw;
height: 100vh;
padding: 16px 8px;
background-color: #fff;
box-sizing: border-box;
section {
padding: 8px 16px;
border: 2px solid transparent;
background-color: #fff;
&:hover {
color: var(--primary-color);
font-weight: 700;
}
&[active="true"] {
border-color: var(--primary-color);
}
span {
width: calc(100% - 32px);
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
}
.file-content {
width: 86vw;
position: relative;
.img-container {
img {
max-height: 100vh;
&:hover {
cursor: pointer;
}
}
}
.error {
background-color: #fff;
img {
width: 500px;
}
}
}
.close-btn {
position: absolute;
top: 12px;
right: 8px;
background-color: transparent;
border: none;
color: #fff;
&:hover {
color: red;
}
}
.rotate-left-btn {
position: absolute;
top: 12px;
right: 118px;
background-color: transparent;
border: none;
color: #fff;
}
.rotate-right-btn {
position: absolute;
top: 12px;
right: 68px;
background-color: transparent;
border: none;
color: #fff;
}
.left-btn {
position: absolute;
top: 50%;
left: 0;
transform: translateY(-50%);
background-color: transparent;
border: none;
color: #fff;
}
.right-btn {
position: absolute;
top: 50%;
right: 0;
transform: translateY(-50%);
background-color: transparent;
border: none;
color: #fff;
}
.download-btn {
position: absolute;
bottom: 20px;
right: 20px;
}
.file-number {
position: absolute;
top: 16px;
left: 18px;
color: #fff;
}
}
</style>

5
src/components/file/upload.vue

@ -9,6 +9,7 @@
@success="handleSuccess"
@error="handleError"
:show-file-list="false"
:accept="accept"
class="mb-16"
>
<el-button
@ -40,6 +41,10 @@ const props = defineProps({
tips: {
type: String,
default: ''
},
accept: {
type: String,
default: '*'
}
});

34
src/components/home/work/index.vue

@ -32,6 +32,17 @@
</div>
</el-tab-pane>
<el-tab-pane name="comfort">
<template #label>
<el-badge :value="myComfortTotal" v-if="comforts.length">
<span class="tab-nav-title">我的抚慰</span>
</el-badge>
<span class="tab-nav-title" v-else>我的抚慰</span>
</template>
<div v-loading="comfortLoading" class="pt-20">
<home-work-my-comfort :data="comforts" @update="getComfortList" />
</div>
</el-tab-pane>
<el-tab-pane name="alarm">
<template #label>
<el-badge :value="myAlarmTotal" v-if="alarms.length">
@ -43,6 +54,7 @@
<home-work-my-alarm :data="alarms" @update="getAlarmList" />
</div>
</el-tab-pane>
</el-tabs>
</template>
<script setup>
@ -50,7 +62,9 @@ import { listTodos } from "@/api/work";
import {
alarmNotificationPageByTodo
} from "@/api/work/alarm";
import {
listComfortTodos
} from "@/api/rightsComfort/comfort";
const activeName = "todo";
const myTodoTotal = ref(0)
const todos = ref([])
@ -73,7 +87,7 @@ function getList() {
});
}
const alarmLoading = ref(true)
const alarmLoading = ref(false)
function getAlarmList() {
alarmLoading.value = true
alarmNotificationPageByTodo({
@ -86,9 +100,25 @@ function getAlarmList() {
});
}
const myComfortTotal = ref(0)
const comfortLoading = ref(false)
const comforts = ref([])
function getComfortList() {
comfortLoading.value = true
listComfortTodos({
current: 1,
size: 100,
}).then((data) => {
comforts.value = data.records;
myComfortTotal.value = data.total
comfortLoading.value = false
});
}
onMounted(() => {
getList();
getAlarmList();
getComfortList();
});
</script>
<style lang="scss" scoped>

105
src/components/home/work/my-comfort.vue

@ -0,0 +1,105 @@
<template>
<div class="table-container">
<el-table :data="data">
<el-table-column
label="抚慰编号"
prop="number"
show-overflow-tooltip
/>
<el-table-column label="申请时间" prop="applyDate" width="160" />
<el-table-column label="事发时间" prop="happenTime" width="160" />
<el-table-column
label="申请人姓名"
prop="applicantEmpName"
width="100"
/>
<el-table-column label="申请人单位" prop="departName" />
<el-table-column label="开户行">
<template #default="{ row }">
<span>{{ row.bankCard }}</span>
<span>{{ row.bankBranch }}</span>
</template>
</el-table-column>
<el-table-column label="状态" width="100">
<template #default="{ row }">
<el-tag
:type="
row.rpcStatus !== 'returned' ? 'primary' : 'danger'
"
v-if="row.rpcStatus"
>{{
getDictLable(dict.comfortStatus, row.rpcStatus)
}}</el-tag
>
</template>
</el-table-column>
<el-table-column label="操作" width="200">
<template #default="{ row }">
<el-button
link
type="primary"
@click="handleShow(row, false)"
v-if="row.rpcStatus !== 'returned'"
>立即处理</el-button
>
<template v-else>
<el-button
link
type="primary"
@click="handleShow(row, true)"
>查看</el-button
>
<!-- <el-button
link
type="primary"
@click="handleReSubmit(row)"
>重新提交</el-button
> -->
<el-button
link
type="danger"
v-if="row.rpcStatus === 'returned'"
@click="handleDelete(row)"
>删除</el-button
>
</template>
</template>
</el-table-column>
</el-table>
</div>
<comfort-dialog
v-model:show="show"
:id="activeRpcId"
:disabled="false"
@update="emit('update')"
/>
</template>
<script setup>
import { getDictLable } from "@/utils/util";
import useCatchStore from "@/stores/modules/catch";
const catchStore = useCatchStore();
const dict = catchStore.getDicts([
"comfortStatus"
]);
defineProps({
data: {
type: Array,
default: [],
},
});
const emit = defineEmits(["update"]);
const show = ref(false);
const activeRpcId = ref('');
function handleShow(row) {
show.value = true;
activeRpcId.value = row.rpcId;
}
</script>
<style lang="scss" scoped>
</style>

8
src/components/negative/action-history.vue

@ -1,14 +1,12 @@
<template>
<div class="flow">
<div class="flow" style="height: 100%">
<header class="flex between v-center flow-header" ref="flowHeaderRef">
<span>
<span class="second mr-8">总耗时</span>
<span style="color: var(--primary-color)">{{
}}</span>
<span style="color: var(--primary-color)">{{}}</span>
</span>
</header>
<el-scrollbar height="300">
<el-scrollbar max-height="calc(100% - 33px)">
<div class="flow-container">
<div v-for="(item, index) in actionHistory" :key="item.id">
<div class="mb-4 mt-4 flow-info">

161
src/components/negative/add.vue

@ -1,7 +1,13 @@
<template>
<el-dialog title="问题下发" width="54vw" :lock-scroll="false" top="5vh">
<el-dialog
title="问题下发"
width="54vw"
:lock-scroll="false"
top="5vh"
style="margin-bottom: 0"
>
<el-scrollbar
height="75vh"
height="78vh"
v-loading="loading"
element-loading-text="问题下发中..."
>
@ -136,11 +142,6 @@
<el-form-item
label="涉嫌问题"
prop="involveProblem"
:rules="{
required: true,
message: '请选择涉嫌问题',
trigger: ['blur'],
}"
>
<el-select
v-model="form.involveProblem"
@ -271,6 +272,84 @@
</el-form-item>
</el-col>
</el-row>
<el-form-item
v-for="(item, index) in form.problems"
:key="index"
:label="`问题${index + 1}`"
>
<div class="flex between v-center" style="width: 100%">
<div class="flex">
<problem-type-select
style="width: 280px"
@change="
(node) =>
handleChangeProblem(node, item)
"
v-model="item.threeLevelCode"
/>
<div style="width: 140px" class="ml-8">
<el-form-item
label-position="top"
:prop="`problems.${index}.threeLevelContentOther`"
:rules="{
required: true,
message: '请输入',
trigger: ['blur'],
}"
style="margin-bottom: 0"
v-if="
item.threeLevelContent === '其他'
"
>
<el-input
placeholder="其他类型详细描述"
v-model="
item.threeLevelContentOther
"
/>
</el-form-item>
</div>
<div style="width: 170px;" class="text-nowrap ml-8">
<span>{{
item.oneLevelContent
? item.oneLevelContent + " / "
: ""
}}</span>
<span>{{
item.twoLevelContent
? item.twoLevelContent + " / "
: ""
}}</span>
<span>{{ item.threeLevelContent }}</span>
</div>
</div>
<el-button
@click="handleRemoveProblem(index)"
plain
type="danger"
size="small"
>
<template #icon>
<icon name="el-icon-Delete" />
</template>
删除问题
</el-button>
</div>
</el-form-item>
<div class="flex center mb-10">
<el-button
@click="handleAddProblem()"
plain
type="primary"
size="small"
>
<template #icon>
<icon name="el-icon-Plus" />
</template>
添加问题
</el-button>
</div>
<el-form-item
label="事情简要描述"
prop="thingDesc"
@ -319,13 +398,25 @@
/>
</el-select>
<div class="tips mt-10">
<p>如主办层级 市局主办 则由<span :danger="form.hostLevel === HostLevel.FIRST">督察支队</span>办理</p>
<p>
如主办层级为
二级机构主办则由<span :danger="form.hostLevel === HostLevel.SECOND">督察部门</span>办理可进一步下发
如主办层级 市局主办 则由<span
:danger="form.hostLevel === HostLevel.FIRST"
>督察支队</span
>办理
</p>
<p>
如主办层级为 三级机构主办则由<span :danger="form.hostLevel === HostLevel.THREE">所队</span>办理
如主办层级为 二级机构主办则由<span
:danger="
form.hostLevel === HostLevel.SECOND
"
>督察部门</span
>办理可进一步下发
</p>
<p>
如主办层级为 三级机构主办则由<span
:danger="form.hostLevel === HostLevel.THREE"
>所队</span
>办理
</p>
</div>
</el-form-item>
@ -412,7 +503,12 @@
trigger: ['blur'],
}"
>
<el-radio-group v-model="form.approvalFlow">
<el-radio-group
v-model="form.approvalFlow"
v-if="
userStore.user.roleCodes.includes('admin_1')
"
>
<el-radio
v-for="item in dict.approvalFlow"
:key="item.dictCode"
@ -423,8 +519,19 @@
}}</el-radio
>
</el-radio-group>
<el-radio-group v-model="form.approvalFlow" v-else>
<el-radio value="2"
>二级审批(所队一>二级机构)</el-radio
>
</el-radio-group>
<div class="tips mt-10">
<p>
<p
v-if="
userStore.user.roleCodes.includes(
'admin_1'
)
"
>
三级审核 在问题提交办结时需经过所队>二级机构>市局三级审核通过后方可办结
</p>
<p>
@ -461,7 +568,10 @@ import feedback from "@/utils/feedback";
import { addNegative, generateOriginId } from "@/api/work/negative";
import { secondList, listByFirstHost } from "@/api/system/depart";
import useCatchStore from "@/stores/modules/catch";
import { disabledDate } from '@/utils/util'
import { disabledDate } from "@/utils/util";
import useUserStore from "@/stores/modules/user";
const userStore = useUserStore();
const catchStore = useCatchStore();
const dict = catchStore.getDicts([
@ -487,7 +597,8 @@ const form = ref({
thingFiles: [],
hostLevel: HostLevel.THREE,
timeLimit: TimeLimit.WORK_137,
approvalFlow: ApprovalFlow.SECOND
approvalFlow: ApprovalFlow.SECOND,
problems: [],
});
watch(
@ -524,7 +635,7 @@ async function handleAddNegative() {
thingFiles: [],
hostLevel: HostLevel.THREE,
timeLimit: TimeLimit.WORK_137,
approvalFlow: ApprovalFlow.SECOND
approvalFlow: ApprovalFlow.SECOND,
};
feedback.msgSuccess("下发成功");
emit("close");
@ -566,14 +677,30 @@ function handleChangeHostLevel(val) {
}
}
function handleAddProblem() {
form.value.problems.push({});
}
function handleRemoveProblem(index) {
form.value.problems.splice(index, 1);
}
function handleChangeProblem(node, problem) {
if (node.level === 3) {
problem.threeLevelContent = node.label;
problem.oneLevelCode = node.parent.parent.key;
problem.oneLevelContent = node.parent.parent.label;
problem.twoLevelCode = node.parent.key;
problem.twoLevelContent = node.parent.label;
}
}
</script>
<style lang="scss" scoped>
.add-negation-container {
padding: 0 60px;
}
.tips {
[danger=true] {
[danger="true"] {
color: var(--danger-color);
}
}

2
src/components/negative/apply-completion.vue

@ -10,8 +10,6 @@
<h3>{{ negative.handleSecondDepartName || '二级机构' }} 市局专班</h3>
<p style="margin-bottom: 40px">逐级审核通过后即可完成办理</p>
</template>
</div>
<footer class="flex end">

2
src/components/negative/apply-countersign.vue

@ -29,7 +29,7 @@
>
<div style="min-height: 200px">
<div class="flex gap-20 mb-10" v-for="(item, index) in formData.countersignDeparts" :key="index">
<div style="width: 280px">
<div style="width: 280px" class="mr-10">
<depart-tree-select v-model="item.id" />
</div>
<el-button type="primary" plain v-if="index === 0" @click="handleAddDepart">

5
src/components/negative/apply-extension.vue

@ -2,9 +2,10 @@
<el-dialog width="50vw" title="申请延期" v-model="show">
<div>
<p>
全流程可延期的总时长不超过{{ negative.maxExtensionDuration }}(中间包括节假日)申请延期需经过
全流程可延期的总时长不超过{{ negative.maxExtensionDuration }}(中间包括节假日)申请延期需经过
</p>
<h3>二级专班 市局</h3>
<h3 v-if="negative.approvalFlow === '3'">{{ negative.handleSecondDepartName }}专班 市局</h3>
<h3 v-else>{{ negative.handleSecondDepartName }}专班</h3>
<p>
审批通过之后才能正式生效在申请延期过程中三级机构仍然可以按照正常流程进行信件的处理如果已提交信件办结申请并通过市局专班的审批则申请延期的流程自动结束
</p>

26
src/components/negative/description.vue

@ -2,13 +2,17 @@
<div class="info-container">
<h3>问题信息</h3>
<div class="row">
<div class="col col-6">
<div class="col col-12">
<label>样本源头编号</label>
<span>{{ negative.originId }}</span>
</div>
<div class="col col-12">
<label>案件/警情编号</label>
<span>{{ negative.caseNumber || '/' }}</span>
</div>
<div class="col col-6">
<label>问题发现时间</label>
<span>{{ negative.discoveryTime }}</span>
<span>{{ negative.discoveryTime || '/' }}</span>
</div>
<div class="col col-6" v-if="negative.happenTime">
<label>问题发生时间</label>
@ -18,8 +22,6 @@
<label>问题来源</label>
<span>{{ negative.problemSources }}</span>
</div>
</div>
<div class="row">
<div class="col col-6" v-if="negative.responderName">
<label>投诉反映人</label>
<span>{{ negative.responderName }}</span>
@ -28,8 +30,6 @@
<label>联系电话</label>
<span>{{ negative.contactPhone }}</span>
</div>
</div>
<div class="row">
<div class="col col-6" v-if="negative.specialSupervision">
<label>专项督察</label>
<span>{{ getDictLable(dict.specialSupervision, negative.specialSupervision) }}</span>
@ -42,24 +42,22 @@
<label>业务类别</label>
<span>{{ negative.businessTypeName }}</span>
</div>
<div class="col col-6">
<div class="col col-6" v-if="negative.policeTypeName">
<label>涉及警种</label>
<span>{{ negative.policeTypeName || '/' }}</span>
<span>{{ negative.policeTypeName }}</span>
</div>
<div class="col col-12">
<label>涉嫌问题</label>
<span>{{ getInvolveProblem(negative.involveProblem, dict.suspectProblem) || '/' }}</span>
</div>
</div>
<div class="row">
<div class="col col-12" v-if="negative.caseNumber">
<label>案件/警情编号</label>
<span>{{ negative.caseNumber }}</span>
</div>
<div class="col col-12">
<label>涉及单位</label>
<span>{{ negative.involveDepartName || '/' }}</span>
</div>
<div class="col col-6">
<label>创建时间</label>
<span>{{ negative.crtTime }}</span>
</div>
</div>
<div>
<div class="text-primary mt-10">事情简要描述</div>

80
src/components/negative/dialog.vue

@ -71,7 +71,8 @@
<el-row style="height: 100%">
<el-col :span="5" style="height: 100%">
<div ref="leftContainerRef" class="left-container h100">
<template
<div
ref="countdownContainerRef"
v-if="
negative.flowKey !==
FlowNodeEnum.FIRST_DISTRIBUTE &&
@ -84,38 +85,52 @@
:max-time="maxDuration"
:extensionDays="negative.extensionDays"
/>
</template>
<div class="row">
<div class="col col-24" style="--label-width: 60px">
</div>
<div class="row" ref="leftRowRef">
<div
class="col col-24"
style="--label-width: 60px"
v-if="negative.timeLimit"
>
<label>办理时限</label>
<span>{{
getDictLable(
dict.timeLimit,
negative.timeLimit
) || "/"
)
}}</span>
</div>
<div class="col col-24" style="--label-width: 60px">
<div
class="col col-24"
style="--label-width: 60px"
v-if="negative.hostLevel"
>
<label>主办层级</label>
<span>{{
getDictLable(
dict.hostLevel,
negative.hostLevel
) || "/"
)
}}</span>
</div>
<div class="col col-24" style="--label-width: 60px">
<div
class="col col-24"
style="--label-width: 60px"
v-if="negative.approvalFlow"
>
<label>审批流程</label>
<span>{{
getDictLable(
dict.approvalFlow,
negative.approvalFlow
) || "/"
)
}}</span>
</div>
</div>
<div ref="actionHistoryRef">
<negative-action-history />
</div>
</div>
</el-col>
<el-col :span="19" style="height: 100%">
<el-scrollbar max-height="100%" class="main-container">
@ -306,10 +321,11 @@
>
<el-tooltip
effect="dark"
:content="`该问题目前正在${negative.currentProcessingObject}等待延期审批,请延期审批通过后再进行提交!`"
:content="`${negative.currentProcessingObject}正在审理您提交的延期审批,请耐心等待审批通过后再操作!`"
raw-content
placement="top"
>
<span class="ml-10">
<el-button
size="large"
:type="item.buttonType"
@ -317,6 +333,7 @@
:disabled="true"
>{{ item.buttonLabel }}</el-button
>
</span>
</el-tooltip>
</template>
<el-button
@ -393,6 +410,7 @@ import { getComponents } from "@/utils/flow";
import { getDictLable } from "@/utils/util";
import useCatchStore from "@/stores/modules/catch";
import { nextTick, onMounted } from "vue";
const dict = useCatchStore().getDicts([
"processingStatus",
@ -558,14 +576,6 @@ function spotCheck() {
}
const dialogRef = ref();
watch(
() => dialogRef.value?.visible,
(val) => {
if (!val) {
spotCheckEditFlag.value = false;
}
}
);
const formData = ref({});
const formRef = ref();
@ -599,6 +609,40 @@ async function handleUpdateVerify() {
defineExpose({
spotCheck,
});
//
const leftContainerRef = ref();
const countdownContainerRef = ref();
const leftRowRef = ref();
const actionHistoryRef = ref();
watch(
() => dialogRef.value?.visible,
(val) => {
if (!val) {
spotCheckEditFlag.value = false;
}
}
);
watch(loading, (val) => {
if (!val) {
nextTick(() => {
console.log("nextTick", [leftContainerRef.value.offsetHeight]);
actionHistoryRef.value.style.height = `${
leftContainerRef.value.offsetHeight -
(countdownContainerRef.value?.offsetHeight || 0) -
leftRowRef.value.offsetHeight
}px`;
console.log(
`${
leftContainerRef.value.offsetHeight -
(countdownContainerRef.value?.offsetHeight || 0) -
leftRowRef.value.offsetHeight
}px`
);
});
}
});
</script>
<style lang="scss" scoped>
.dialog-header {

27
src/components/negative/verify-description.vue

@ -40,6 +40,23 @@
<span>{{ negative.rectifyDesc }}</span>
</div>
</div>
<div class="row" v-if="negative.unrectifyReason">
<div class="col col-24">
<label>问题未整改原因</label>
<span>{{ negative.unrectifyReason }}</span>
</div>
</div>
<div class="row" v-if="negative.handlePolices.length > 0">
<div class="col col-24">
<label>经办人</label>
<span>
<div v-for="item in negative.handlePolices" :key="item" class="mr-20">
<span class="mr-8">{{ item.name }}</span>
<span class="text-primary">{{ item.empNo }}</span>
</div>
</span>
</div>
</div>
</el-collapse-item>
<el-collapse-item
v-for="(blame, index) in negative.blames.filter(
@ -52,7 +69,10 @@
<div class="row">
<div class="col col-6">
<label>涉及人员姓名</label>
<span>{{ blame.blameName }} {{ blame.blameEmpNo }}</span>
<span>
<span>{{ blame.blameName }}</span>
<span class="text-primary ml-10">{{ blame.blameEmpNo }}</span>
</span>
</div>
<div class="col col-6">
<label>身份证</label>
@ -132,11 +152,12 @@
<div class="row" style="background: #f5f5f5">
<div class="col col-6">
<label>涉及领导姓名</label>
<span>{{ blame.leadName }} {{ blame.leadEmpNo }}</span>
<span v-if="blame.leadName">{{ blame.leadName }} {{ blame.leadEmpNo }}</span>
<span v-else>/</span>
</div>
<div class="col col-6">
<label>身份证</label>
<span>{{ blame.leadIdCode }}</span>
<span>{{ blame.leadIdCode || '/' }}</span>
</div>
<div class="col col-6" v-if="blame.leadResponsibilityTypeName">

74
src/components/negative/verify.vue

@ -455,7 +455,9 @@
<div
class="flex center"
style="width: 100%"
v-if="item.problems.length === 0"
v-if="
!item.problems || item.problems.length === 0
"
>
<el-button
@click="handleAddProblem(item)"
@ -518,7 +520,7 @@
trigger: ['blur'],
}"
>
<div class="flex gap">
<div class="flex gap v-center">
<el-radio-group
v-model="item.subjectiveAspectCode"
@change="
@ -547,6 +549,8 @@
item.subjectiveAspectCode ===
SubjectiveAspect.OTHER
"
style="margin-bottom: 0"
class="ml-20"
>
<el-input
v-model="
@ -1123,10 +1127,28 @@
"
>
<el-radio
v-for="item in dict.superviseMeasures"
:key="item.dictCode"
:value="item.dictValue"
>{{ item.dictLabel }}
v-for="dictItem in dict.superviseMeasures"
:key="dictItem.dictCode"
:value="dictItem.dictValue"
@click.native.prevent="
() => {
if (
item.superviseMeasuresCode ===
dictItem.dictValue
) {
item.superviseMeasuresCode =
'';
item.superviseMeasuresName =
'';
} else {
item.superviseMeasuresCode =
dictItem.dictValue;
item.superviseMeasuresName =
dictItem.dictLabel;
}
}
"
>{{ dictItem.dictLabel }}
</el-radio>
</el-radio-group>
</el-form-item>
@ -1244,6 +1266,26 @@
</el-button>
</div>
</div>
<div
class="flex center"
style="width: 100%"
v-if="
!item.problems ||
item.problems.length === 0
"
>
<el-button
@click="handleAddProblem(item)"
plain
type="primary"
size="small"
>
<template #icon>
<icon name="el-icon-Plus" />
</template>
添加问题
</el-button>
</div>
</el-form-item>
</div>
</el-form-item>
@ -1549,7 +1591,7 @@ function handleAddPersonal() {
});
if (form.value.blameLeaders.length == 0) {
handleAddBlameLeader()
handleAddBlameLeader();
}
}
@ -1558,6 +1600,9 @@ function handleRemovePersonal(item) {
}
function handleAddProblem(blame) {
if (!blame.problems) {
blame.problems = [];
}
blame.problems.push({});
}
@ -1630,6 +1675,10 @@ watch(
);
function handleChangeCheckStatus(val, item) {
if (val === "4") {
form.value.checkStatusName = "无法办理";
return;
}
form.value.checkStatusName = dict.inspectCase.filter(
(item) => item.dictValue === val
)[0].dictLabel;
@ -1690,6 +1739,17 @@ function handleChangeResultCode(item) {
}
}
function handleChangeLeadResultCode(item) {
if (item.leadHandleResultCode && item.leadHandleResultCode.length > 0) {
item.leadHandleResultName = dict.handleResult
.filter((obj) => item.leadHandleResultCode.includes(obj.dictValue))
.map((obj) => obj.dictLabel)
.join("、");
} else {
item.leadHandleResultName = "";
}
}
function handleChangeDepartResultCode(item) {
if (item.handleResultCode && item.handleResultCode.length > 0) {
item.handleResultName = dict.departHandleResult

1
src/components/negativeInfo/depart-dialog.vue

@ -1,7 +1,6 @@
<template>
<el-dialog
title="单位问题详情"
v-model="show"
width="85vw"
top="1vh"
style="margin: 1vh auto"

7
src/components/query-select.vue

@ -67,7 +67,12 @@ function handleCheck(val) {
}
}
.query-check {
gap: 4px;
>* {
margin-right: 4px;
&:last-child {
margin-right: 0;
}
}
span {
padding: 2px 4px;
border: 1px solid transparent;

60
src/components/video-play.vue

@ -0,0 +1,60 @@
<template>
<div ref="playerRef" class="video-container"></div>
</template>
<script setup>
import { nextTick } from "vue";
const props = defineProps({
url: {
type: String,
default: ''
},
showOperateBtns: {
type: Boolean,
default: true
}
})
const playerRef = ref();
let jessibucaPlayer;
onMounted(() => {
//
nextTick(() => {
playerRef.value.style.height = playerRef.value.scrollWidth * 0.6 + 'px'
})
let operateBtns = {}
if (props.showOperateBtns) {
operateBtns = {
screenshot: true, //
fullscreen: true, //
play: true, //
audio: true, //
record: false, //
}
}
jessibucaPlayer = new Jessibuca({
container: playerRef.value,
isFlv: true, // 使flv
showBandwidth: false, // 使
isResize: false,
operateBtns,
loadingText: "加载中...",
});
if (props.url) {
jessibucaPlayer.play(props.url);
}
});
watch(() => props.url, (url) => {
if (url) {
jessibucaPlayer.play(url);
}
})
</script>
<style lang="scss">
.video-container {
background-color: #0d0e1b;
}
</style>

20
src/layout/components/Aside.vue

@ -51,12 +51,12 @@
</a>
</nav>
</el-scrollbar>
<button
<!-- <button
class="flex center v-center pointer expand-btn"
@click="handleAsideCollapse"
>
<!-- <icon name="el-icon-ArrowLeftBold" :size="58" /> -->
</button>
<icon name="el-icon-ArrowLeftBold" :size="58" />
</button> -->
</aside>
</template>
<script setup>
@ -115,7 +115,12 @@ aside {
transition: width height 0.6s;
}
.menu-item {
gap: 20px;
> * {
margin-right: 20px;
&:last-child {
margin-right: 0;
}
}
height: 56px;
padding: 0 18px;
display: flex;
@ -127,7 +132,12 @@ aside {
color: #fff;
}
section {
gap: 16px;
> * {
margin-right: 16px;
&:last-child {
margin-right: 0;
}
}
}
.el-button {
color: #656fac;

4
src/router/routes.ts

@ -95,10 +95,6 @@ export const routes = [
path: '/datav/subOneRightsComfort',
component: () => import('@/views/datav/subonedatav/SubOneRightsComfort.vue'),
},
{
path: '/work/verifySubmit',
component: () => import('@/views/work/VerifySubmit.vue'),
},
{
path: '/system/Operating',
component: () => import('@/views/system/Operating.vue'),

59
src/style/public.scss

@ -111,28 +111,59 @@ svg + span {
.flex.gap-4,
.flex-inline.gap-4 {
gap: 4px;
>* {
margin-right: 4px;
&:last-child {
margin-right: 0;
}
}
}
.flex.gap,
.flex-inline.gap {
gap: 8px;
>* {
margin-right: 8px;
&:last-child {
margin-right: 0;
}
}
}
.flex.gap-10 {
gap: 10px;
>* {
margin-right: 10px;
&:last-child {
margin-right: 0;
}
}
}
.flex.gap-12 {
gap: 12px;
>* {
margin-right: 12px;
&:last-child {
margin-right: 0;
}
}
}
.flex.gap-16 {
gap: 16px;
margin-right: 16px;
&:last-child {
margin-right: 0;
}
}
.flex.gap-20 {
gap: 20px;
margin-right: 20px;
&:last-child {
margin-right: 0;
}
}
.text-small {
@ -357,7 +388,8 @@ svg + span {
--gap-width: 10px;
display: flex;
gap: var(--gap-width);
&.col-4 {
width: 16.6%;
}
@ -386,6 +418,7 @@ svg + span {
width: var(--label-width);
text-align: right;
color: #999;
margin-right: var(--gap-width);
}
>span {
@ -502,25 +535,33 @@ svg + span {
}
.form-row {
margin-bottom: 18px;
margin-bottom: 8px;
font-size: 14px;
label {
width: 120px;
line-height: 32px;
padding-right: 12px;
box-sizing: border-box;
text-align: right;
&+* {
width: calc(100% - 126px);
}
}
.btn-box {
width: 70px;
}
.el-form-item {
margin-bottom: 0;
}
}
.query-box {
gap: 10px 20px;
> * {
margin-right: 10px;
margin-bottom: 10px;
}
}

4
src/utils/feedback.ts

@ -40,8 +40,8 @@ export class Feedback {
})
}
// 弹出提示
alert(msg: string) {
ElMessageBox.alert(msg, '系统提示')
alert(msg: string, title: string) {
ElMessageBox.alert(msg, title || '系统提示')
}
// 错误提示
alertError(msg: string) {

347
src/views/books/Audit.vue

@ -0,0 +1,347 @@
<template>
<div class="container">
<header>
<el-form :label-width="120">
<el-row>
<el-col :span="6">
<el-form-item label="问题发现时间">
<date-time-range-picker-ext
v-model="query.discoveryTime"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="问题录入时间">
<date-time-range-picker-ext
v-model="query.crtTime"
/>
</el-form-item>
</el-col>
</el-row>
<div class="form-row flex">
<label class="text-center">问题信息</label>
<div class="flex wrap query-box">
<el-input
placeholder="问题编号 / 样本源头编号"
v-model="query.originId"
clearable
style="width: 200px"
/>
<el-input
placeholder="涉及案件 / 警情编号"
v-model="query.caseNumber"
clearable
style="width: 200px"
/>
<el-input
placeholder="事情简要描述"
v-model="query.thingDesc"
clearable
style="width: 260px"
/>
<el-select
style="width: 146px"
placeholder="业务类别"
clearable
v-model="query.businessTypeCode"
>
<el-option
v-for="item in dict.businessType"
:key="item.id"
:label="item.dictLabel"
:value="item.dictValue"
/>
</el-select>
<el-tree-select
:data="dictProblemSources"
:props="{ value: 'id' }"
node-key="id"
v-model="query.problemSourcesCode"
clearable
filterable
multiple
collapse-tags
style="width: 200px"
placeholder="问题来源"
/>
</div>
</div>
<div class="form-row flex">
<label class="text-center">核查情况</label>
<div class="flex wrap query-box">
<div style="width: 200px">
<depart-tree-select
v-model="query.involveDepartId"
placeholder="涉及单位"
/>
</div>
<div style="width: 200px">
<depart-tree-select
v-model="query.handleDepartId"
placeholder="办理单位"
/>
</div>
<el-select
style="width: 120px"
placeholder="是否属实"
clearable
v-model="query.checkStatus"
>
<el-option
v-for="item in dict.inspectCase"
:key="item.id"
:label="item.dictLabel"
:value="item.dictValue"
/>
</el-select>
<el-select
style="width: 120px"
placeholder="是否整改"
clearable
v-model="query.isRectifyCode"
>
<el-option
v-for="item in dict.isRectify"
:key="item.id"
:label="item.dictLabel"
:value="item.dictValue"
/>
</el-select>
<div class="flex gap-4">
<el-select
v-model="query.blameKey"
style="width: 90px"
@change="delete query.blameValue"
>
<el-option value="name" label="姓名" />
<el-option value="empNo" label="警号" />
<el-option value="idCode" label="身份证" />
</el-select>
<el-input
placeholder="涉及人员"
v-model="query.blameValue"
clearable
style="width: 190px"
/>
</div>
</div>
</div>
<div class="form-row flex">
<label class="text-center">其他选项</label>
<div class="flex wrap query-box">
<el-select
style="width: 200px"
placeholder="流程阶段"
clearable
v-model="query.flowKey"
>
<el-option
v-for="item in flowNodes"
:key="item.flowKey"
:label="item.flowName"
:value="item.flowKey"
/>
</el-select>
<el-select
style="width: 120px"
placeholder="办理状态"
clearable
v-model="query.processingStatus"
multiple
>
<el-option
v-for="item in dict.processingStatus"
:key="item.id"
:label="item.dictLabel"
:value="item.dictValue"
/>
</el-select>
<el-select
style="width: 160px"
placeholder="办理中是否超时"
clearable
v-model="query.handleTimeoutFlag"
>
<el-option label="未超时" :value="false" />
<el-option label="已超时" :value="true" />
</el-select>
<el-select
style="width: 140px"
placeholder="办结是否超时"
clearable
v-model="query.timeoutFlag"
>
<el-option label="办结未超时" :value="false" />
<el-option label="办结超时" :value="true" />
</el-select>
<el-select
style="width: 120px"
placeholder="申请延期"
clearable
v-model="query.extensionFlag"
>
<el-option label="已申请" :value="true" />
<el-option label="未申请" :value="false" />
</el-select>
</div>
</div>
</el-form>
<div class="flex between mt-20 mb-26">
<el-button type="primary" @click="handleExport"
>数据导出
</el-button>
<div>
<el-button type="primary" @click="getList">
<template #icon
><icon name="el-icon-Search"
/></template>
查询</el-button
>
<el-button @click="reset">重置</el-button>
</div>
</div>
</header>
<div class="table-container">
<el-table :data="list">
<el-table-column
label="业务类型"
prop="businessTypeName"
width="140"
/>
<el-table-column
label="问题来源"
prop="problemSources"
width="160"
/>
<el-table-column
label="问题发现时间"
prop="discoveryTime"
width="160"
/>
<el-table-column
label="案件/警情编号"
prop="caseNumber"
width="160"
/>
<el-table-column
label="具体内容"
prop="thingDesc"
show-overflow-tooltip
/>
<el-table-column
label="整改情况"
prop="rectifyDesc"
show-overflow-tooltip
/>
<el-table-column
label="涉及单位"
prop="involveDepartName"
width="180"
/>
<el-table-column label="办理单位" show-overflow-tooltip>
<template #default="{ row }">
<span
>{{ row.handleSecondDepartName
}}{{ row.handleThreeDepartName }}</span
>
</template>
</el-table-column>
<el-table-column label="操作" width="120">
<template #default="{ row }">
<el-button
type="primary"
link
@click="handleAction(row)"
>详情</el-button
>
</template>
</el-table-column>
</el-table>
</div>
<div class="flex end mt-8">
<el-pagination
@size-change="getList"
@current-change="getList"
:page-sizes="[10, 20, 50]"
v-model:page-size="query.size"
v-model:current-page="query.current"
layout="total, sizes, prev, pager, next"
:total="total"
>
</el-pagination>
</div>
</div>
<negative-dialog
v-model="show"
:id="activeNegativeId"
@close="show = false"
/>
</template>
<script setup>
import { BASE_PATH } from "@/api/request";
import { ProblemSources } from "@/enums/dictEnums";
import feedback from "@/utils/feedback";
import { getDictLable } from "@/utils/util";
import useCatchStore from "@/stores/modules/catch";
import { listNegativeAudit } from "@/api/books.ts";
const catchStore = useCatchStore();
const flowNodes = catchStore.getFlowNodes();
const dictProblemSources = catchStore.getDictProblemSources();
const dict = catchStore.getDicts([
"inspectCase",
"businessType",
"processingStatus",
"isRectify"
]);
const query = ref({
size: 10,
current: 1,
blameKey: "name",
});
const list = ref([]);
const total = ref(0);
function getList() {
listNegativeAudit(query.value).then((data) => {
list.value = data.records;
total.value = data.total;
});
}
function reset() {
query.value = {
size: 10,
current: 1,
blameKey: "name",
};
getList();
}
getList();
function handleExport() {
window.open(
`${BASE_PATH}/negative/books/export/audit?` +
new URLSearchParams(query.value).toString()
);
}
const show = ref(false);
const activeNegativeId = ref("");
function handleAction(row) {
show.value = true;
activeNegativeId.value = row.id;
}
</script>
<style lang="scss" scoped>
</style>

3
src/views/books/Gabxf.vue

@ -2,9 +2,6 @@
<div class="container">
<header>
<el-form :label-width="80">
<el-row>
<el-col :span="6"> </el-col>
</el-row>
<div class="form-row flex">
<label class="text-center">基本信息</label>
<div class="flex wrap query-box">

185
src/views/books/Mail12337.vue

@ -1,9 +1,192 @@
<template>
<div class="container">
<header>
<el-form :label-width="114">
<el-row>
<el-col :span="6">
<el-form-item label="投诉人">
<div class="flex gap">
<el-select
v-model="query.responderKey"
style="width: 160px"
@change="delete query.responderValue"
>
<el-option value="name" label="姓名" />
<el-option value="phone" label="电话" />
</el-select>
<el-input
placeholder="请输入"
v-model="query.responderValue"
clearable
/>
</div>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="登记时间">
<date-time-range-picker-ext
v-model="query.discoverTime"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="具体内容">
<el-input
placeholder="请输入"
v-model="query.thingDesc"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div class="mb-25 flex between">
<div>
<el-button type="primary" @click="handleExport"
>数据导出
</el-button>
</div>
<div>
<el-button type="primary" @click="getList">
<template #icon>
<icon name="el-icon-Search" />
</template>
查询
</el-button>
<el-button @click="reset">重置</el-button>
</div>
</div>
</header>
<div class="table-container">
<el-table :data="list">
<el-table-column
label="信件编号"
prop="onlyId"
show-overflow-tooltip
width="180"
/>
<el-table-column
label="投诉渠道"
prop="letterSource"
width="120"
/>
<el-table-column
label="登记时间"
prop="discoverTime"
width="150"
/>
<el-table-column label="投诉人" prop="name" width="90" />
<el-table-column label="电话" prop="phone" width="116" />
<el-table-column label="被投诉机构" show-overflow-tooltip>
<template #default="{ row }">
<span>{{ row.secondDepartName }}</span>
<span>{{ row.thirdDepartName }}</span>
</template>
</el-table-column>
<el-table-column
label="具体内容"
prop="wjwfProject"
show-overflow-tooltip
/>
<el-table-column
label="是否属实"
prop="checkStatusName"
width="120"
/>
<el-table-column
label="核查简要情况"
prop="checkStatusDesc"
show-overflow-tooltip
/>
<el-table-column label="操作" width="120">
<template #default="{ row }">
<el-button
type="primary"
link
@click="handleAction(row)"
:disabled="!row.id"
>详情</el-button
>
</template>
</el-table-column>
</el-table>
</div>
<div class="flex end mt-8">
<el-pagination
@size-change="getList"
@current-change="getList"
:page-sizes="[10, 20, 50]"
v-model:page-size="query.size"
v-model:current-page="query.current"
layout="total, sizes, prev, pager, next"
:total="total"
>
</el-pagination>
</div>
</div>
<negative-dialog
v-model="show"
:id="activeNegativeId"
@close="show = false"
/>
</template>
<script setup>
import { BASE_PATH } from "@/api/request";
import { ProblemSources } from "@/enums/dictEnums";
import feedback from "@/utils/feedback";
import { getDictLable } from "@/utils/util";
import useCatchStore from "@/stores/modules/catch";
import { listPetitionComplaint12337Books } from "@/api/data/petition12337.ts";
const catchStore = useCatchStore();
const dict = catchStore.getDicts(["distributionState", "inspectCase"]);
const query = ref({
size: 10,
current: 1,
responderKey: "name",
});
const list = ref([]);
const total = ref(0);
function getList() {
listPetitionComplaint12337Books(query.value).then((data) => {
list.value = data.records;
total.value = data.total;
});
}
function reset() {
query.value = {
size: 10,
current: 1,
responderKey: "name",
};
getList();
}
getList();
function handleExport() {
window.open(
`${BASE_PATH}/negative/books/export/mail12337?` +
new URLSearchParams(query.value).toString()
);
}
const show = ref(false);
const activeNegativeId = ref("");
function handleAction(row) {
show.value = true;
activeNegativeId.value = row.id;
}
</script>
<style lang="scss" scoped>
</style>

91
src/views/data/Ajhc.vue

@ -47,7 +47,10 @@
</el-col>
<el-col :span="6">
<el-form-item label="分发状态">
<el-select v-model="query.distributionState" clearable>
<el-select
v-model="query.distributionState"
clearable
>
<el-option
v-for="item in dict.distributionState"
:key="item.id"
@ -60,10 +63,7 @@
<el-col :span="6">
<el-form-item label="是否属实">
<el-select
clearable
v-model="query.checkStatus"
>
<el-select clearable v-model="query.checkStatus">
<el-option
v-for="item in dict.inspectCase"
:key="item.id"
@ -73,15 +73,13 @@
</el-select>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div class="mb-25 flex between">
<div>
<el-button type="primary" @click="show = true"
>数据导入
</el-button
>
</el-button>
<el-badge
:value="distributeList.length"
class="ml-10"
@ -91,8 +89,7 @@
type="primary"
@click="distributeListShow = true"
>问题下发
</el-button
>
</el-button>
</el-badge>
</div>
<div>
@ -101,8 +98,7 @@
<icon name="el-icon-Search" />
</template>
查询
</el-button
>
</el-button>
<el-button @click="reset">重置</el-button>
</div>
</div>
@ -158,7 +154,8 @@
</el-table-column>
<el-table-column label="状态">
<template #default="{ row }">
<el-tag>{{
<el-tag
>{{
getDictLable(
dict.distributionState,
row.distributionState
@ -169,7 +166,9 @@
</el-table-column>
<el-table-column label="操作" width="200">
<template #default="{ row }">
<el-button type="primary" link @click="handleDetail(row)" v-if="row.distributionState === '1'"
>问题详情
</el-button>
<template
v-if="
row.distributionState ===
@ -186,22 +185,19 @@
).length === 0
"
>加入问题下发
</el-button
>
</el-button>
<el-button
type="info"
link
v-else
@click="handleRemoveDistribute(row)"
>移除
</el-button
>
</el-button>
</template>
<el-button type="danger" link @click="handleDel(row)"
>删除
</el-button
>
</el-button>
</template>
</el-table-column>
</el-table>
@ -257,7 +253,6 @@
prop="discoveryTime"
show-overflow-tooltip
/>
<!-- <el-table-column label="问题发生时间" prop="happenTime" show-overflow-tooltip />-->
<el-table-column
label="问题来源"
prop="problemSources"
@ -275,7 +270,6 @@
/>
<el-table-column label="业务类别" prop="businessTypeName" />
<el-table-column label="涉嫌问题" prop="involveProblem" />
<!-- <el-table-column label="涉及警种" prop="policeTypeName" />-->
<el-table-column
label="涉及单位"
prop="involveDepartName"
@ -287,14 +281,12 @@
/>
<el-table-column label="操作" width="140">
<template #default="{ row }">
<el-button
type="info"
link
@click="handleRemoveDistribute(row)"
>移除
</el-button
>
</el-button>
</template>
</el-table-column>
</el-table>
@ -307,8 +299,7 @@
@click="handleShowDistributeDialog"
:disabled="distributeList.length === 0"
>确认数据
</el-button
>
</el-button>
</footer>
</el-dialog>
@ -342,11 +333,9 @@
v-for="item in dict.approvalFlow"
:key="item.dictCode"
:value="item.dictValue"
>{{
item.dictLabel
>{{ item.dictLabel
}}{{ item.remark ? `(${item.remark})` : "" }}
</el-radio
>
</el-radio>
</el-radio-group>
<div class="tips mt-10">
<p>
@ -359,15 +348,17 @@
</el-form-item>
</el-form>
<footer class="flex end mt-20">
<el-button
type="primary"
size="large"
@click="handleSubmit"
<el-button type="primary" size="large" @click="handleSubmit"
>确认下发
</el-button
>
</el-button>
</footer>
</el-dialog>
<negative-dialog
v-model="negativeShow"
:id="activeNegativeId"
@close="negativeShow = false"
/>
</template>
<script setup>
import { BASE_PATH } from "@/api/request";
@ -375,6 +366,7 @@ import {
listCaseVerif,
delCaseVerif,
distributeCaseVerif,
getNegativeId
} from "@/api/data/caseVerif";
import { DistributionState } from "@/enums/dictEnums";
import { getDictLable } from "@/utils/util";
@ -438,7 +430,7 @@ function handleShowDistributeDialog() {
}
const form = ref({});
const formRef = ref()
const formRef = ref();
function handleRemoveDistribute(row) {
distributeList.value.splice(
@ -450,14 +442,21 @@ function handleRemoveDistribute(row) {
}
async function handleSubmit() {
await formRef.value.validate()
form.value.data = distributeList.value
await distributeCaseVerif(form.value)
form.value = {}
distributeShow.value = false
distributeListShow.value = false
feedback.msgSuccess('下发成功')
getList()
await formRef.value.validate();
form.value.data = distributeList.value;
await distributeCaseVerif(form.value);
form.value = {};
distributeShow.value = false;
distributeListShow.value = false;
feedback.msgSuccess("下发成功");
getList();
}
const negativeShow = ref(false)
const activeNegativeId = ref('')
async function handleDetail(row) {
activeNegativeId.value = await getNegativeId(row.originId)
negativeShow.value = true
}
</script>
<style lang="scss" scoped>

49
src/views/data/Gabxf.vue

@ -3,6 +3,21 @@
<header>
<el-form :label-width="114">
<el-row>
<el-col :span="6">
<el-form-item label="登记时间">
<date-time-range-picker-ext
v-model="query.discoveryTime"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="录入时间">
<date-time-range-picker-ext
v-model="query.createTime"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="信件编号">
<el-input
@ -30,13 +45,6 @@
</div>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="登记时间">
<date-time-range-picker-ext
v-model="query.discoveryTime"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="具体内容">
<el-input
@ -45,6 +53,28 @@
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="被投诉机构">
<depart-tree-select
v-model="query.departId"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="初重信访">
<el-select
clearable
v-model="query.initialPetition"
>
<el-option
v-for="item in dict.initialPetition"
:key="item.id"
:label="item.dictLabel"
:value="item.dictValue"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="状态">
<el-select
@ -239,10 +269,7 @@ import useCatchStore from "@/stores/modules/catch";
const catchStore = useCatchStore();
const dict = catchStore.getDicts([
"distributionState",
"timeLimit",
"approvalFlow",
"distributionFlow",
"distributionState",
"initialPetition"
]);
const query = ref({

46
src/views/data/Gjxf.vue

@ -3,6 +3,21 @@
<header>
<el-form :label-width="114">
<el-row>
<el-col :span="6">
<el-form-item label="登记时间">
<date-time-range-picker-ext
v-model="query.discoveryTime"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="录入时间">
<date-time-range-picker-ext
v-model="query.createTime"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="信件编号">
<el-input
@ -30,13 +45,6 @@
</div>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="登记时间">
<date-time-range-picker-ext
v-model="query.discoveryTime"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="具体内容">
<el-input
@ -45,6 +53,28 @@
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="被投诉机构">
<depart-tree-select
v-model="query.departId"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="初重信访">
<el-select
clearable
v-model="query.initialPetition"
>
<el-option
v-for="item in dict.initialPetition"
:key="item.id"
:label="item.dictLabel"
:value="item.dictValue"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="状态">
<el-select
@ -234,7 +264,7 @@ import { getDictLable } from "@/utils/util";
import useCatchStore from "@/stores/modules/catch";
const catchStore = useCatchStore();
const dict = catchStore.getDicts(["distributionState"]);
const dict = catchStore.getDicts(["distributionState", "initialPetition"]);
const query = ref({
size: 10,

129
src/views/data/ImportRecords.vue

@ -0,0 +1,129 @@
<template>
<div class="container">
<header>
<el-form :label-width="120">
<el-row>
<el-col :span="6">
<el-form-item label="数据来源">
<el-select v-model="query.source" clearable>
<el-option value="公安部信访">公安部信访</el-option>
<el-option value="国家信访">国家信访</el-option>
<el-option value="案件核查">案件核查</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="创建时间">
<date-time-range-picker-ext v-model="query.crtTime"/>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div class="flex end mb-20">
<el-button type="primary" @click="getList">
<template #icon>
<icon name="el-icon-Search" />
</template>
查询</el-button
>
<el-button @click="reset">重置</el-button>
</div>
</header>
<div class="table-container" v-loading="loading">
<el-table :data="list">
<el-table-column label="数据来源" prop="source" show-overflow-tooltip />
<el-table-column
label="导入数量"
prop="importRow"
align="center"
/>
<el-table-column label="操作时间" prop="crtTime" />
<el-table-column label="操作人" prop="crtUser" />
<el-table-column label="状态" prop="status">
<template #default="{ row }">
<el-tag type="success" v-if="row.status === '0'"
>导入成功</el-tag
>
<el-tag type="danger" v-else-if="row.status === '1'"
>导入失败</el-tag
>
</template>
</el-table-column>
</el-table>
</div>
<div class="flex end mt-8">
<el-pagination
@size-change="getList"
@current-change="getList"
:page-sizes="[10, 20, 50]"
v-model:page-size="query.size"
v-model:current-page="query.current"
layout="total, sizes, prev, pager, next"
:total="total"
>
</el-pagination>
</div>
</div>
</template>
<script setup>
import { BASE_PATH } from "@/api/request";
import { listNegativeTask } from "@/api/work/negativeTask";
const list = ref([]);
const query = ref({
size: 10,
current: 1,
category: '1'
});
const total = ref(0);
const loading = ref(true)
function getList() {
loading.value = true
listNegativeTask(query.value).then((data) => {
list.value = data.records;
total.value = data.total;
loading.value = false
});
}
function reset() {
query.value = {
size: 10,
current: 1,
category: '1'
};
getList();
}
onMounted(() => {
getList();
});
function handleDownload(row) {
if (row.status !== '1') {
}
fetch(`${BASE_PATH}/file/stream${row.filePath}`)
.then((response) => {
console.log(response);
return response.blob();
})
.then((res) => {
console.log(res);
const blob = new Blob([res], {
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
});
const url = window.URL.createObjectURL(blob);
const link = document.createElement("a");
link.href = url;
link.setAttribute("download", row.taskName + ".xlsx");
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
window.URL.revokeObjectURL(url);
});
}
</script>
<style lang="scss" scoped>
</style>

6
src/views/data/Mail12337.vue

@ -203,6 +203,7 @@
</div>
</template>
</el-upload>
<div class="mt-10">说明请上传12337信访投诉台账表格进行导入操作上传成功后点击下一步进行数据核验</div>
</div>
</template>
<template v-if="activeStep === 1">
@ -383,6 +384,7 @@
/>
</el-table>
</div>
<div class="mt-10">说明数据校验展示信访投诉关键信息标红内容为必填项</div>
<div class="text-danger text-wrap mt-10 text-small">
{{ errMsg }}
</div>
@ -577,7 +579,7 @@ const router = useRouter();
const query = ref({
size: 10,
current: 1,
problemSourcesCode: ProblemSources.XF12337,
responderValue: 'name'
});
const list = ref([]);
@ -594,7 +596,7 @@ function reset() {
query.value = {
size: 10,
current: 1,
problemSourcesCode: ProblemSources.XF12337,
responderValue: 'name'
};
getList();
}

196
src/views/data/Mailbox.vue

@ -0,0 +1,196 @@
<template>
<div class="container">
<header>
<el-form :label-width="114">
<el-row>
<el-col :span="6">
<el-form-item label="信件编号">
<el-input
placeholder="请输入"
v-model="query.originId"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="投诉人">
<div class="flex gap">
<el-select
v-model="query.responderKey"
style="width: 160px"
@change="delete query.responderValue"
>
<el-option value="name" label="姓名" />
<el-option value="phone" label="电话" />
</el-select>
<el-input
placeholder="请输入"
v-model="query.responderValue"
clearable
/>
</div>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="来信时间">
<date-time-range-picker-ext
v-model="query.discoveryTime"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="具体内容">
<el-input
placeholder="请输入"
v-model="query.thingDesc"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div class="mb-25 flex end">
<div>
<el-button type="primary" @click="getList">
<template #icon>
<icon name="el-icon-Search" />
</template>
查询</el-button
>
<el-button @click="reset">重置</el-button>
</div>
</div>
</header>
<div class="table-container">
<el-table :data="list">
<el-table-column
label="信件编号"
prop="originId"
show-overflow-tooltip
/>
<el-table-column
label="来信时间"
prop="discoveryTime"
show-overflow-tooltip
/>
<el-table-column
label="投诉人"
prop="responderName"
width="90"
/>
<el-table-column label="电话" prop="contactPhone" />
<el-table-column
label="具体内容"
prop="thingDesc"
show-overflow-tooltip
/>
<el-table-column label="办理单位" show-overflow-tooltip>
<template #default="{ row }">
<span>{{ row.handleSecondDepartName }}</span>
<span>{{ row.handleThreeDepartName }}</span>
</template>
</el-table-column>
<el-table-column
label="是否属实"
prop="checkStatusName"
width="100"
align="center"
/>
<el-table-column label="办理状态" width="110">
<template #default="{ row }">
<el-tag
:type="
row.processingStatus ===
ProcessingStatus.COMPLETED
? 'success'
: 'primary'
"
v-if="row.processingStatus"
>{{
getDictLable(
dict.processingStatus,
row.processingStatus
)
}}</el-tag
>
</template>
</el-table-column>
<el-table-column label="操作" width="200">
<template #default="{ row }">
<el-button
type="primary"
link
@click="handleAction(row)"
>详情</el-button
>
</template>
</el-table-column>
</el-table>
</div>
<div class="flex end mt-8">
<el-pagination
@size-change="getList"
@current-change="getList"
:page-sizes="[10, 20, 50]"
v-model:page-size="query.size"
v-model:current-page="query.current"
layout="total, sizes, prev, pager, next"
:total="total"
>
</el-pagination>
</div>
</div>
<negative-dialog
v-model="show"
:id="activeNegativeId"
@close="show = false"
/>
</template>
<script setup>
import { ProcessingStatus } from "@/enums/flowEnums";
import {
listMailbox
} from "@/api/data/mailbox";
import feedback from "@/utils/feedback";
import { getDictLable } from "@/utils/util";
import useCatchStore from "@/stores/modules/catch";
const catchStore = useCatchStore();
const dict = catchStore.getDicts(["distributionState"]);
const query = ref({
size: 10,
current: 1,
responderKey: "name",
});
const list = ref([]);
const total = ref(0);
function getList() {
listMailbox(query.value).then((data) => {
list.value = data.records;
total.value = data.total;
});
}
function reset() {
query.value = {
size: 10,
current: 1,
responderKey: "name",
};
getList();
}
getList();
const show = ref(false);
const activeNegativeId = ref("");
function handleAction(row) {
show.value = true;
activeNegativeId.value = row.id;
}
</script>
<style lang="scss" scoped>
</style>

376
src/views/data/VideoInspection.vue

@ -1,5 +1,7 @@
<template>
<div class="container">
<el-tabs>
<el-tab-pane label="未下发">
<header>
<el-form :label-width="114">
<el-row>
@ -78,13 +80,28 @@
>
</template>
</el-table-column>
<el-table-column label="预警类别" prop="systemKeyName" />
<el-table-column
label="预警类别"
prop="systemKeyName"
/>
<el-table-column label="预警时间" prop="rqsj" />
<el-table-column label="案事件名称" prop="title" />
<el-table-column label="发生单位名称" prop="fsdwGajgmc" />
<el-table-column
label="发生单位名称"
prop="fsdwGajgmc"
/>
<el-table-column label="下发状态" width="120">
<template #default="{ row }">
<span class="text-danger">未下发</span>
<span
class="text-danger"
v-if="row.distributionState === '0'"
>未下发</span
>
<span
class="text-success"
v-if="row.distributionState === '1'"
>已下发</span
>
</template>
</el-table-column>
<el-table-column label="操作" width="160">
@ -92,7 +109,7 @@
<el-button
type="primary"
link
@click="handleShowInfo(row)"
@click="handleShowInfo(row, false)"
>查看详情</el-button
>
<el-button
@ -117,6 +134,221 @@
>
</el-pagination>
</div>
</el-tab-pane>
<el-tab-pane label="已下发">
<header>
<el-form :label-width="114">
<el-row>
<el-col :span="6">
<el-form-item label="预警类型">
<el-input
placeholder="请输入"
v-model="query2.systemKeyName"
clearable
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="案事件名称">
<el-input
placeholder="请输入"
v-model="query2.title"
clearable
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="发生单位">
<depart-tree-select
v-model="query2.departId"
placeholder="涉及单位"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div class="flex end mt-20 mb-26">
<div>
<el-button type="primary" @click="getList2">
<template #icon
><icon name="el-icon-Search"
/></template>
查询</el-button
>
<el-button @click="reset1">重置</el-button>
</div>
</div>
</header>
<div class="table-container">
<el-table :data="list2">
<el-table-column
label="预警级别"
prop="alarmLevel"
width="100"
align="center"
>
<template #default="{ row }">
<span v-if="row.alarmLevel"
>{{ row.alarmLevel }}</span
>
</template>
</el-table-column>
<el-table-column
label="预警类别"
prop="systemKeyName"
/>
<el-table-column label="预警时间" prop="rqsj" />
<el-table-column label="案事件名称" prop="title" />
<el-table-column
label="发生单位名称"
prop="fsdwGajgmc"
/>
<el-table-column
label="操作时间"
width="120"
prop="updateTime"
/>
<el-table-column label="下发状态" width="120">
<template #default="{ row }">
<span
class="text-danger"
v-if="row.distributionState === '0'"
>未下发</span
>
<span
class="text-success"
v-if="row.distributionState === '1'"
>已下发</span
>
</template>
</el-table-column>
<el-table-column label="操作" width="180">
<template #default="{ row }">
<el-button
type="primary"
link
@click="handleShowInfo(row, true)"
>查看详情</el-button
>
</template>
</el-table-column>
</el-table>
</div>
<div class="flex end mt-8">
<el-pagination
@size-change="getList2"
@current-change="getList2"
:page-sizes="[10, 20, 50]"
v-model:page-size="query2.size"
v-model:current-page="query2.current"
layout="total, sizes, prev, pager, next"
:total="total2"
>
</el-pagination>
</div>
</el-tab-pane>
<el-tab-pane label="无效">
<header>
<el-form :label-width="114">
<el-row>
<el-col :span="6">
<el-form-item label="预警类型">
<el-input
placeholder="请输入"
v-model="query1.systemKeyName"
clearable
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="案事件名称">
<el-input
placeholder="请输入"
v-model="query1.title"
clearable
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="发生单位">
<depart-tree-select
v-model="query1.departId"
placeholder="涉及单位"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div class="flex end mt-20 mb-26">
<div>
<el-button type="primary" @click="getList1">
<template #icon
><icon name="el-icon-Search"
/></template>
查询</el-button
>
<el-button @click="reset1">重置</el-button>
</div>
</div>
</header>
<div class="table-container">
<el-table :data="list1">
<el-table-column
label="预警级别"
prop="alarmLevel"
width="100"
align="center"
>
<template #default="{ row }">
<span v-if="row.alarmLevel"
>{{ row.alarmLevel }}</span
>
</template>
</el-table-column>
<el-table-column
label="预警类别"
prop="systemKeyName"
/>
<el-table-column label="预警时间" prop="rqsj" />
<el-table-column label="案事件名称" prop="title" />
<el-table-column
label="发生单位名称"
prop="fsdwGajgmc"
/>
<el-table-column
label="操作时间"
width="120"
prop="updateTime"
/>
<el-table-column label="操作" width="180">
<template #default="{ row }">
<el-button
type="primary"
link
@click="handleShowInfo(row, true)"
>查看详情</el-button
>
<el-button link @click="handleRestore(row)"
>恢复数据</el-button
>
</template>
</el-table-column>
</el-table>
</div>
<div class="flex end mt-8">
<el-pagination
@size-change="getList1"
@current-change="getList1"
:page-sizes="[10, 20, 50]"
v-model:page-size="query1.size"
v-model:current-page="query1.current"
layout="total, sizes, prev, pager, next"
:total="total1"
>
</el-pagination>
</div>
</el-tab-pane>
</el-tabs>
</div>
<el-dialog
@ -140,19 +372,19 @@
>{{ info.alarmLevel }}</span
>
</div>
<div class="col col-12">
<div class="col col-6">
<label>登记单位</label>
<span>{{ info.registrationDepartName }}</span>
</div>
<div class="col col-12">
<div class="col col-6">
<label>发生单位</label>
<span>{{ info.happenDepartName }}</span>
</div>
<div class="col col-24">
<div class="col col-12">
<label>督察方式</label>
<span>{{ info.systemKeyName }}</span>
</div>
<div class="col col-24">
<div class="col col-12">
<label>预警标题</label>
<span>{{ info.title }}</span>
</div>
@ -184,29 +416,36 @@
</el-scrollbar>
</el-col>
<el-col :span="19">
<el-scrollbar height="560px">
<div style="height: calc(96vh - 260px)">
<div class="row">
<div class="col col-24">
<div class="col col-12">
<label>发生单位</label>
<span>{{ info.happenDepartName }}</span>
</div>
<div class="col col-24">
<div class="col col-12">
<label>预警时间</label>
<span>{{ activeZl.dmtbzrqsj }}</span>
</div>
</div>
<div>
<img
style="width: 100%"
:src="activeZl.dzwjwz"
alt=""
/>
<div
style="height: calc(100% - 32px)"
class="flex center"
>
<img :src="activeZl.dzwjwz" alt="" />
</div>
</div>
</el-scrollbar>
</el-col>
</el-row>
</div>
<footer class="flex end mt-20">
<footer class="flex end mt-20" style="min-height: 40px">
<template v-if="!disabledFlag">
<el-button
size="large"
type="danger"
@click="handleUpdateState"
v-if="!distributeList.includes(activeRow)"
>查否</el-button
>
<el-button
size="large"
@click="handleJoin"
@ -224,6 +463,7 @@
<el-button size="large" type="primary" @click="handleNext"
>下一条</el-button
>
</template>
</footer>
</el-dialog>
@ -467,6 +707,7 @@ import {
listVideoInspection,
getVideoInspectionInfo,
distributeData,
updateState,
} from "@/api/data/videoInspection";
import feedback from "@/utils/feedback";
import useCatchStore from "@/stores/modules/catch";
@ -485,28 +726,82 @@ const dict = catchStore.getDicts([
const query = ref({
current: 1,
size: 10,
state: "1",
distributionState: "0",
});
const list = ref([]);
const total = ref(0);
function getList() {
listVideoInspection(query.value).then((data) => {
let pages = 1;
async function getList() {
const data = await listVideoInspection(query.value);
list.value = data.records;
total.value = data.total;
});
pages = data.pages;
}
onMounted(() => {
getList();
getList1();
getList2();
});
function reset() {
query.value = {
current: 1,
size: 10,
state: "1",
distributionState: '0'
};
getList();
}
//------------------------------
const query1 = ref({
current: 1,
size: 10,
state: "0",
});
const list1 = ref([]);
const total1 = ref(0);
async function getList1() {
const data = await listVideoInspection(query1.value);
list1.value = data.records;
total1.value = data.total;
}
function reset1() {
query1.value = {
current: 1,
size: 10,
state: "0",
};
getList1();
}
//------------------------------
const query2 = ref({
current: 1,
size: 10,
state: "1",
distributionState: '1'
});
const list2 = ref([]);
const total2 = ref(0);
async function getList2() {
const data = await listVideoInspection(query2.value);
list2.value = data.records;
total2.value = data.total;
}
function reset2() {
query2.value = {
current: 1,
size: 10,
state: "1",
distributionState: "1",
};
getList2();
}
const show = ref(false);
const infoLoading = ref(false);
@ -514,10 +809,11 @@ const info = ref({});
const activeZl = ref({});
const activeRow = ref({});
async function handleShowInfo(row) {
const disabledFlag = ref(false);
async function handleShowInfo(row, disabled) {
activeRow.value = row;
show.value = true;
disabledFlag.value = disabled;
}
const manualShow = ref(false);
@ -567,14 +863,27 @@ async function handleSubmit() {
submitLoading.value = false;
throw e;
}
distributeShow.value = false;
manualShow.value = false;
submitLoading.value = false;
getList();
getList2();
distributeList.value = [];
await feedback.confirm("问题已下发,请到“综合查询”页面查看");
router.push("/query");
}
function handleNext() {
async function handleNext() {
let index = list.value.indexOf(activeRow.value);
if (index === list.value.length - 1) {
if (query.value.current === pages) {
infoLoading.value = false;
feedback.alert("当前已是最后一条数据!", "温馨提示");
return;
}
query.value.current += 1;
infoLoading.value = true;
await getList();
index = 0;
} else {
index++;
@ -592,6 +901,23 @@ watch(activeRow, async () => {
}
infoLoading.value = false;
});
async function handleUpdateState() {
await feedback.confirm("确认要将该数据判断为无效?");
infoLoading.value = true;
await updateState(activeRow.value.id, "0");
getList();
getList1();
handleNext();
}
async function handleRestore(row) {
await feedback.confirm("确认要恢复该数据?");
infoLoading.value = true;
await updateState(row.id, "1");
getList();
getList1();
}
</script>
<style scoped lang="scss">
.top-container {

288
src/views/datav/AuditSuper.vue

@ -5,33 +5,28 @@
<main>
<el-row :gutter="16">
<el-col :span="6">
<datav-card title="审计整改结果" sub-title="已整改问题数/查出问题数">
<datav-card
title="审计整改结果"
sub-title="已整改问题数/查出问题数"
>
<el-scrollbar height="350px">
<datav-chart-bar
:size="small"
size="small"
:data="data1"
unit="%"
remark-font-size="12px"
spanClass="right-aligned"
:color="colors"
/>
</el-scrollbar>
</datav-card>
<datav-card title="审计查出问题" style="height: 500px">
<v-charts
style="height: 300px"
:option="option22"
autoresize
/>
</datav-card>
</el-col>
<el-col :span="12">
@ -80,7 +75,6 @@
</el-col>
<el-col :span="6">
<datav-card title="审计项目类型">
<datav-tabs>
<datav-tab-item label="政府投资审计" name="1">
<div class="mb-40">
@ -110,7 +104,6 @@
</div>
</datav-tab-item>
</datav-tabs>
</datav-card>
<datav-card title="审计工作动态">
<el-scrollbar height="470px">
@ -121,7 +114,11 @@
:title="msg.workType"
:content="msg.contentTxt"
:date="msg.releaseTime"
/>
>
<template #link>
<div class="message-link" @click="handlePerviewFile(msg)" v-if="msg.files">查看图片</div>
</template>
</datav-message>
</el-scrollbar>
</datav-card>
</el-col>
@ -129,6 +126,8 @@
</main>
</div>
</el-scrollbar>
<file-preview :files="files" v-model:show="filePreviewShow" />
</template>
@ -149,94 +148,94 @@ const temp = ref({
tempTotalMon: 0,
tempReviewMon: 0,
tempCheckPro: 0,
tempPro: 0
})
tempPro: 0,
});
setTimeout(() => {
temp.value = {
tempTotal: 462,
tempTotalMon: 79224.59,
tempReviewMon: 3544.01,
tempCheckPro: 1192,
tempPro: 389
}
tempPro: 389,
};
}, 1000);
let gobalTempMapVoList = [
{
"name": "天心分局",
"reviewOrg": 0,
"checkPro": 0,
"rushPro": 0,
"changed": 0
name: "天心分局",
reviewOrg: 0,
checkPro: 0,
rushPro: 0,
changed: 0,
},
{
"name": "开福分局",
"reviewOrg": 0,
"checkPro": 186,
"rushPro": 0,
"changed": 137
name: "开福分局",
reviewOrg: 0,
checkPro: 186,
rushPro: 0,
changed: 137,
},
{
"name": "岳麓分局",
"reviewOrg": 0,
"checkPro": 11,
"rushPro": 0,
"changed": 0
name: "岳麓分局",
reviewOrg: 0,
checkPro: 11,
rushPro: 0,
changed: 0,
},
{
"name": "望城分局",
"reviewOrg": 0,
"checkPro": 0,
"rushPro": 0,
"changed": 0
name: "望城分局",
reviewOrg: 0,
checkPro: 0,
rushPro: 0,
changed: 0,
},
{
"name": "浏阳市局",
"reviewOrg": 0,
"checkPro": 0,
"rushPro": 0,
"changed": 0
name: "浏阳市局",
reviewOrg: 0,
checkPro: 0,
rushPro: 0,
changed: 0,
},
{
"name": "长沙县局",
"reviewOrg": 0,
"checkPro": 0,
"rushPro": 0,
"changed": 0
name: "长沙县局",
reviewOrg: 0,
checkPro: 0,
rushPro: 0,
changed: 0,
},
{
"name": "芙蓉分局",
"reviewOrg": 0,
"checkPro": 1,
"rushPro": 0,
"changed": 1
name: "芙蓉分局",
reviewOrg: 0,
checkPro: 1,
rushPro: 0,
changed: 1,
},
{
"name": "雨花分局",
"reviewOrg": 0,
"checkPro": 240,
"rushPro": 0,
"changed": 220
name: "雨花分局",
reviewOrg: 0,
checkPro: 240,
rushPro: 0,
changed: 220,
},
{
"name": "宁乡市局",
"reviewOrg": 0,
"checkPro": 232,
"rushPro": 194,
"changed": 194
}
name: "宁乡市局",
reviewOrg: 0,
checkPro: 232,
rushPro: 194,
changed: 194,
},
];
echarts.registerMap("changsha", changshaMap);
const option = ref({
geo: {
map: "changsha",
},
tooltip: {
trigger: 'item',
trigger: "item",
formatter: function (params) {
console.log(params)
const dataItem = gobalTempMapVoList.find(item => item.name.includes(params.name.substring(0, 2)));
console.log(params);
const dataItem = gobalTempMapVoList.find((item) =>
item.name.includes(params.name.substring(0, 2))
);
if (dataItem) {
return `
<div class="tooltip">
@ -268,9 +267,11 @@ const option = ref({
type: "piecewise",
bottom: 10,
pieces: [
{min: 0, max: 500, label: "问题数低于500"}, {min: 501, max: 1000, label: "问题数介于500-1000"}, {
{ min: 0, max: 500, label: "问题数低于500" },
{ min: 501, max: 1000, label: "问题数介于500-1000" },
{
min: 1001,
label: "问题数高于1000"
label: "问题数高于1000",
},
],
right: 10,
@ -281,7 +282,7 @@ const option = ref({
},
calculable: true,
inRange: {
color: ["#4987F6", "#F6A149", "#D34343",],
color: ["#4987F6", "#F6A149", "#D34343"],
},
},
series: [
@ -298,32 +299,44 @@ const option = ref({
normal: {
areaColor: "#02215E",
borderColor: "#24D2EE",
borderWidth: 1 //
borderWidth: 1, //
},
},
emphasis: {
areaColor: "#FFD700", //
borderColor: "#FF0000", //
borderWidth: 4 //
borderWidth: 4, //
},
data: [],
}
},
],
})
});
const option1 = ref({
xAxis: {
type: "category",
boundaryGap: false,
data: ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月",],
data: [
"1月",
"2月",
"3月",
"4月",
"5月",
"6月",
"7月",
"8月",
"9月",
"10月",
"11月",
],
},
tooltip: {
trigger: 'axis',
trigger: "axis",
axisPointer: {
type: 'line',
type: "line",
label: {
backgroundColor: '#6a7985'
}
}
backgroundColor: "#6a7985",
},
},
},
yAxis: {
type: "value",
@ -332,14 +345,14 @@ const option1 = ref({
lineStyle: {
color: "#193775",
},
}
},
},
series: [
{
type: "line",
smooth: true,
label: {
show: false
show: false,
},
lineStyle: {
color: "#28E6FF",
@ -420,31 +433,31 @@ const data1 = [
const data2 = [
{
name: "开福分局",
value: 9700
value: 9700,
},
{
name: "芙蓉分局",
value: 9021
value: 9021,
},
{
name: "岳麓分局",
value: 8512
value: 8512,
},
{
name: "雨花分局",
value: 8021
value: 8021,
},
{
name: "望城分局",
value: 7111
value: 7111,
},
{
name: "浏阳市局",
value: 6622
value: 6622,
},
{
name: "长沙县局",
value: 6221
value: 6221,
},
];
const option2 = {
@ -478,11 +491,17 @@ const option3 = {
color: "#fff",
},
data: [
{value: 321, name: "提取、查封、扣押、冻结、处置涉案财物不规范"},
{
value: 321,
name: "提取、查封、扣押、冻结、处置涉案财物不规范",
},
{ value: 249, name: "法律文书填制不规范" },
{ value: 215, name: "未上缴或未及时上缴涉案资金" },
{ value: 190, name: "随身财务登记、保管、处置不规范" },
{value: 88, name: "执法活动财务管理制度不健全、管理责任不落实"},
{
value: 88,
name: "执法活动财务管理制度不健全、管理责任不落实",
},
{ value: 55, name: "未按规定退还保证金" },
{ value: 13, name: "涉案财务保管场所设施配备不规范" },
{ value: 6, name: "随身财务登记、保管、处置不规范" },
@ -503,8 +522,11 @@ const option4 = {
},
data: [
{ value: 8, name: "法律文书填写不规范" },
{value: 3, name: "提取、查封、扣押、冻结、处置涉案财物不规范"},
{value: 1, name: "\"三公经费\"预算执行及公开不符合规定"},
{
value: 3,
name: "提取、查封、扣押、冻结、处置涉案财物不规范",
},
{ value: 1, name: '"三公经费"预算执行及公开不符合规定' },
{ value: 1, name: "随身财务登记、保管、处置不规范" },
{ value: 1, name: "未按规定退还保证金" },
{ value: 1, name: "未上缴或未及时上缴涉案资金" },
@ -567,25 +589,32 @@ const colors = [
percentage: 80,
},
{
//
color: "linear-gradient( 270deg, #FB002D 0%, #822232 100%)",
percentage: 70,
},
];
const getWorkDynamicsData = async () => {
const res = await getWorkDynamics(time.value);
const colorNewsVoList = workDynamicColorMapping(res.newsVoList);
const data = await getWorkDynamics(time.value);
const colorNewsVoList = workDynamicColorMapping(data);
messages.value = colorNewsVoList;
}
};
const getData = () => {
getWorkDynamicsData();
}
};
onMounted(() => {
getData();
});
const files = ref([])
const filePreviewShow = ref(false)
function handlePerviewFile(msg) {
if (msg.files) {
filePreviewShow.value = true
files.value = JSON.parse(msg.files)
}
}
</script>
@ -598,8 +627,12 @@ onMounted(() => {
position: relative;
width: 169.88px;
height: 155px;
background: linear-gradient(180deg, rgba(1, 4, 87, 0.8) 0%, rgba(3, 21, 119, 0.8) 100%);
border: 1px solid #4E8FFF;
background: linear-gradient(
180deg,
rgba(1, 4, 87, 0.8) 0%,
rgba(3, 21, 119, 0.8) 100%
);
border: 1px solid #4e8fff;
margin: -10px -10px -10px -10px;
}
@ -607,19 +640,22 @@ onMounted(() => {
.tooltip-title {
width: 169.88px;
height: 43px;
background: linear-gradient(180deg, rgba(1, 4, 87, 0.8) 0%, rgba(3, 21, 119, 0.8) 100%);
background: linear-gradient(
180deg,
rgba(1, 4, 87, 0.8) 0%,
rgba(3, 21, 119, 0.8) 100%
);
display: flex;
justify-content: center; /* 水平居中 */
align-items: center; /* 垂直居中 */
text-align: center; /* 水平居中 */
font-weight: 400;
font-size: 16px;
color: #FFFFFF;
color: #ffffff;
line-height: 22px;
border-bottom: 1px solid #253755; /* 设置下边框 */
}
.tooltip-content {
width: 170px;
height: 106px;
@ -631,17 +667,15 @@ onMounted(() => {
.tooltip-content ul {
list-style-type: none; /* 移除默认的小圆点 */
padding: 0;
}
.tooltip-content ul li {
margin-left: 5px;
height: 25px;
color: #597AE9;
color: #597ae9;
font-size: 13px;
}
// span
.tooltip-ul span {
float: right;
@ -652,10 +686,9 @@ onMounted(() => {
font-size: 13px;
}
/* 小尖角 */
.tooltip::before {
content: '';
content: "";
position: absolute;
top: 90px; /* 调整尖角的垂直位置 */
left: -10px; /* 调整尖角的水平位置 */
@ -665,22 +698,31 @@ onMounted(() => {
//border-bottom: 10px solid green; /* */
//border-right: 10px solid blue; /* */
}
}
.message {
padding: 10px;
margin-bottom: 10px;
background: linear-gradient(270deg, rgba(16, 151, 255, 0.1) 0%, rgba(0, 55, 236, 0.87) 100%);
&[type=warning] {
background: linear-gradient(270deg, rgba(255, 190, 16, 0.1) 0%, rgba(236, 84, 0, 0.87) 100%);
background: linear-gradient(
270deg,
rgba(16, 151, 255, 0.1) 0%,
rgba(0, 55, 236, 0.87) 100%
);
&[type="warning"] {
background: linear-gradient(
270deg,
rgba(255, 190, 16, 0.1) 0%,
rgba(236, 84, 0, 0.87) 100%
);
}
&[type=success] {
background: linear-gradient(270deg, rgba(91, 216, 9, 0.14) 0%, #28813D 100%);
&[type="success"] {
background: linear-gradient(
270deg,
rgba(91, 216, 9, 0.14) 0%,
#28813d 100%
);
}
.message-title {
@ -693,7 +735,15 @@ onMounted(() => {
}
}
.message-link {
font-size: 12px;
color: #eee;
&:hover {
cursor: pointer;
text-decoration: underline;
}
}
</style>

48
src/views/datav/CaseVerif.vue

@ -485,17 +485,7 @@ const jbcloption = ref({
label: {
color: "#fff",
},
data: [
// {value: 14, name: ""},
// {value: 11, name: ""},
// {value: 3, name: ""},
// {value: 2, name: ""},
// {value: 12, name: ""},
// {value: 8, name: ""},
// {value: 2, name: ""},
// {value: 2, name: ""},
// {value: 3, name: ""},
],
data: [],
},
],
});
@ -510,17 +500,7 @@ const tzcloption = ref({
label: {
color: "#fff",
},
data: [
// {value: 14, name: ""},
// {value: 11, name: ""},
// {value: 3, name: ""},
// {value: 2, name: ""},
// {value: 12, name: ""},
// {value: 8, name: ""},
// {value: 2, name: ""},
// {value: 2, name: ""},
// {value: 3, name: ""},
],
data: [],
},
],
});
@ -695,23 +675,23 @@ const setupEventListeners = () => {
};
const caseVerifRankAnimationStop = () => {
const temp = caseVerifRankTabs.value.$el;
temp.addEventListener('mouseenter', () => {
temp?.addEventListener('mouseenter', () => {
clearInterval(caseVerifRankIntervalId)
});
temp.addEventListener('mouseleave', () => {
temp?.addEventListener('mouseleave', () => {
clearInterval(caseVerifRankIntervalId); //
caseVerifRankIntervalId = setInterval(caseVerifRankAnimation, 3000);
});
}
const caseVerifProPropertyAnimationStop = () => {
const temp = zfbaProProperty?.value?.chart;
temp.on('mousemove', (e) => {
temp?.on('mousemove', (e) => {
clearInterval(caseVerifProPropertyIntervalId);
temp.dispatchAction({type: "downplay", seriesIndex: 0,});
temp.dispatchAction({type: "highlight", seriesIndex: 0, dataIndex: e.dataIndex,});
temp.dispatchAction({type: "showTip", seriesIndex: 0, dataIndex: e.dataIndex,});
})
temp.on('mouseout', () => {
temp?.on('mouseout', () => {
clearInterval(caseVerifProPropertyIntervalId);
caseVerifProPropertyIntervalId = setInterval(caseVerifProPropertyAnimation, 2000);
})
@ -719,50 +699,50 @@ const caseVerifProPropertyAnimationStop = () => {
const caseVerifMapAnimationStop = () => {
const mapTemp = caseVerifMap?.value?.chart;
//
mapTemp.on('mousemove', (e) => {
mapTemp?.on('mousemove', (e) => {
clearInterval(caseVerifMapIntervalId);
mapTemp.dispatchAction({type: "downplay", seriesIndex: 0,});
mapTemp.dispatchAction({type: "highlight", seriesIndex: 0, dataIndex: e.dataIndex,});
mapTemp.dispatchAction({type: "showTip", seriesIndex: 0, dataIndex: e.dataIndex,});
});
//
mapTemp.on('mouseout', () => {
mapTemp?.on('mouseout', () => {
clearInterval(caseVerifMapIntervalId); //
caseVerifMapIntervalId = setInterval(caseVerifMapAnimation, 2000);
});
}
const caseVerifTrendAnimationStop = () => {
const temp = caseVerifProTrend?.value.getDom();
temp.addEventListener('mouseenter', () => {
temp?.addEventListener('mouseenter', () => {
clearInterval(caseVerifTrendIntervalId);
});
temp.addEventListener('mouseleave', () => {
temp?.addEventListener('mouseleave', () => {
clearInterval(caseVerifTrendIntervalId);
caseVerifTrendIntervalId = setInterval(caseVerifTrendAnimation, 1000);
});
}
const caseVerifCaseSourceRateAnimationStop = () => {
const temp = caseSourceRate?.value?.chart;
temp.on('mousemove', (e) => {
temp?.on('mousemove', (e) => {
clearInterval(caseVerifCaseSourceIntervalId);
temp.dispatchAction({type: "downplay", seriesIndex: 0,});
temp.dispatchAction({type: "highlight", seriesIndex: 0, dataIndex: e.dataIndex,});
temp.dispatchAction({type: "showTip", seriesIndex: 0, dataIndex: e.dataIndex,});
})
temp.on('mouseout', () => {
temp?.on('mouseout', () => {
clearInterval(caseVerifCaseSourceIntervalId);
caseVerifCaseSourceIntervalId = setInterval(caseVerifCaseSourceRateAnimation, 2000);
})
}
const caseVerifJbclSituationAnimationStop = () => {
const temp = jbclSituation?.value?.chart;
temp.on('mousemove', (e) => {
temp?.on('mousemove', (e) => {
clearInterval(caseVerifJbclSituationIntervalId);
temp.dispatchAction({type: "downplay", seriesIndex: 0,});
temp.dispatchAction({type: "highlight", seriesIndex: 0, dataIndex: e.dataIndex,});
temp.dispatchAction({type: "showTip", seriesIndex: 0, dataIndex: e.dataIndex,});
})
temp.on('mouseout', () => {
temp?.on('mouseout', () => {
clearInterval(caseVerifJbclSituationIntervalId);
caseVerifJbclSituationIntervalId = setInterval(caseVerifJbclSituationAnimation, 2000);
})

4
src/views/datav/Jwpy.vue

@ -390,7 +390,7 @@ const handleOrgChange = async (checkedOrg) => {
if (chart) {
chart.dispatchAction({type: 'highlight', name: targetName,});
} else {
alert("没有找到")
}
console.log("年份" + selectYear.value + " 月份" + selectMonth.value + " 单位" + selectOrg.value + " task" + task.value)
} catch (error) {
@ -431,7 +431,7 @@ const handleChartClick = async (params) => {
//
const discovery = async () => {
//
await GetZHMYLPM(selectYear.value, selectMonth.value, selectOrg.value, task.value, 2).then((res) => {
await GetZHMYLPM(selectYear.value, selectMonth.value, selectOrg.value, task.value, 1).then((res) => {
tableData1.value = res[0].lstCity
let temp = res[0].lstSheng;
//

1244
src/views/datav/SceneInsp.vue

File diff suppressed because it is too large Load Diff

71
src/views/datav/VideoInsp.vue

@ -21,24 +21,19 @@
</div>
</div>
<div class="mb-12">
<iframe
:src="activeVideoUrl"
style="height: 180px"
></iframe>
<VideoPlay :url="activeUrl" :showOperateBtns="false" />
</div>
<el-scrollbar max-width="100%">
<div class="flex gap" style="width: 840px">
<div
v-for="item in videos"
v-for="(item, index) in videos"
:key="item"
@click="activeVideoUrl = item.url"
@click="handlePlay(item, index)"
style="width: 160px"
>
<img
:src="item.img"
:active="
activeVideoUrl === item.url
"
:src="item.imgUrl"
:active="activeVideoIndex === index"
/>
</div>
</div>
@ -67,7 +62,6 @@
<el-scrollbar height="280px">
<datav-chart-bar
:data="jsdwRankList"
:max="11"
size="large"
:color="colors"
/>
@ -212,6 +206,8 @@
</template>
<script setup>
import LivePlayer from "@liveqing/liveplayer-v3";
import changshaMap from "@/assets/data/changsha.json";
import vCharts from "vue-echarts";
import * as echarts from "echarts/core";
@ -501,16 +497,16 @@ const getVideoSuperviseMapData = async (timeValue) => {
{
gte: 0,
lte: range60Percent,
label: "低于最大问题的60%",
label: "低于最大问题的60%",
color: "#4987F6",
},
{
gte: range60Percent,
lte: range80Percent,
label: "介于最大问题的60%~80%",
label: "介于最大问题的60%~80%",
color: "#F6A149",
},
{ gte: range80Percent, label: "高于最大问题80%", color: "#D34343" },
{ gte: range80Percent, label: "高于最大问题数的80%", color: "#D34343" },
];
};
const getVideoSuperviseTrendData = async (year) => {
@ -564,7 +560,7 @@ const videoMapAnimation = () => {
});
};
// 2
videoMapIntervalId = setInterval(videoMapAnimation, 2000);
// videoMapIntervalId = setInterval(videoMapAnimation, 2000);
//
const videoTrendAnimation = () => {
const trendTemp = videoProTrend?.value?.chart;
@ -697,43 +693,34 @@ const videoProblemTypeRateAnimationStop = () => {
);
});
};
// endregion
const videos = [
{
url: "http://65.47.6.105:18080/#/play/wasm/ws%3A%2F%2F65.47.6.105%3A8080%2Frtp%2F43012457021185000003_34020000001320000033.live.flv",
img: `/v2/imgs/video/1.jpg`,
},
{
url: "http://65.47.6.105:18080/#/play/wasm/ws%3A%2F%2F65.47.6.105%3A8080%2Frtp%2F43012457021185000003_34020000001320000028.live.flv",
img: `/v2/imgs/video/2.jpg`,
},
{
url: "http://65.47.6.105:18080/#/play/wasm/ws%3A%2F%2F65.47.6.105%3A8080%2Frtp%2F43012457021185000003_34020000001320000002.live.flv",
img: `/v2/imgs/video/3.jpg`,
},
{
url: "http://65.47.6.105:18080/#/play/wasm/ws%3A%2F%2F65.47.6.105%3A8080%2Frtp%2F43012457021185000003_34020000001320000019.live.flv",
img: `/v2/imgs/video/4.jpg`,
},
{
url: "http://65.47.6.105:18080/#/play/wasm/ws%3A%2F%2F65.47.6.105%3A8080%2Frtp%2F43012457021185000003_34020000001320000011.live.flv",
img: `/v2/imgs/video/5.jpg`,
},
];
const activeVideoUrl = ref(videos[0].url);
import { listVideoConfigByDepartId } from '@/api/system/videoConfig'
const videos = ref([]);
const activeUrl = ref('');
const videoStatus = ref({
all: 0,
percentage: '0%',
on: 0
percentage: "0%",
on: 0,
});
onMounted(() => {
getVideoStatus().then((data) => {
videoStatus.value = data;
});
listVideoConfigByDepartId('12630').then(data => {
videos.value = data;
if (data.length > 0) {
activeUrl.value = data[0].videoUrl
}
})
});
const activeVideoIndex = ref(0);
function handlePlay(item, index) {
activeVideoIndex.value = index;
activeUrl.value = item.videoUrl;
}
</script>
<style lang="scss" scoped>

2
src/views/datav/subonedatav/SubOneAuditSuper.vue

@ -10,7 +10,7 @@
<el-scrollbar height="350px">
<datav-chart-bar
:size="small"
size="small"
:data="data1"
unit="%"
remark-font-size="12px"

2
src/views/datav/subonedatav/SubOneCaseVerif.vue

@ -253,7 +253,7 @@ const option = ref({
formatter: function (params) {
console.log(params)
const dataItem = gobalTempMapVoList.value.find(item => item.name === params.name) || {}; //
console.log("Data item:", dataItem);
if (dataItem.name === params.name) {
return `
<div class="tooltip">

3
src/views/datav/subonedatav/SubOneMailVisits.vue

@ -577,8 +577,7 @@ const option = ref({
position: 'bottom',
formatter: function (params) {
const dataItem = mailMapIconList.value.find(item => item.name === params.name) || {}; //
// console.log("Data item:", dataItem);
console.log("Data item:", mailMapIconList.value);
//
if (dataItem.name === params.name) {
return `

10
src/views/datav/subonedatav/SubOneSceneInsp.vue

@ -58,7 +58,7 @@
<el-scrollbar height="350px">
<datav-chart-bar
:data="fxsjChangedRankList"
:size="small"
size="small"
title="整改率排名"
sub-title="已整改/问题数"
unit="%"
@ -113,7 +113,7 @@
<el-scrollbar height="350px">
<datav-chart-bar
:data="jsdwChangedRankList"
:size="small"
size="small"
title="整改率排名"
sub-title="已整改/问题数"
unit="%"
@ -964,7 +964,7 @@ const option = ref({
position: 'bottom',
formatter: function (params) {
const dataItem = superviseTempMapVoList.value.find(item => item.name === params.name) || {}; //
console.log("Data item:", dataItem);
if (dataItem.name === params.name) {
return `
<div class="tooltip">
@ -1217,8 +1217,8 @@ const getSubOneCheckBeerData = async (departId, times) => {
}
const getSubOneWorkDynamicsData = async (departId, times) => {
const res = await getSubOneWorkDynamics(departId, times);
const colorNewsVoList = workDynamicColorMapping(res.newsVoList);
const data = await getSubOneWorkDynamics(departId, times);
const colorNewsVoList = workDynamicColorMapping(data);
messages.value = colorNewsVoList;
}
const getData = async () => {

436
src/views/datav/subonedatav/SubOneVideoInsp.vue

@ -9,33 +9,44 @@
<div class="row mt-4 mb-20">
<div class="col col-8">
<label>视频总数</label>
<span>107</span>
<span>{{ videoStatus.all }}</span>
</div>
<div class="col col-8">
<label>在线数</label>
<span>97</span>
<span>{{ videoStatus.on }}</span>
</div>
<div class="col col-8">
<label>在线率</label>
<span>91%</span>
<span>{{ videoStatus.percentage }}</span>
</div>
</div>
<div class="mb-12">
<VideoPlay
:url="activeUrl"
:showOperateBtns="false"
/>
</div>
<el-row :gutter="12">
<el-col :span="8">
<img src="/imgs/datav/1.png" class="active" alt=""/>
</el-col>
<el-col :span="8">
<img src="/imgs/datav/2.jpg" alt=""/>
</el-col>
<el-col :span="8">
<img src="/imgs/datav/3.jpeg" alt=""/>
</el-col>
</el-row>
<el-scrollbar max-width="100%">
<div class="flex gap" style="width: 840px">
<div
v-for="(item, index) in videos"
:key="item"
@click="handlePlay(item, index)"
style="width: 160px"
>
<img
:src="item.imgUrl"
:active="activeVideoIndex === index"
/>
</div>
</div>
</el-scrollbar>
</datav-card>
<datav-card title="问题数排名" sub-title="问题数" style="height: 370px;">
<datav-card
title="问题数排名"
sub-title="问题数"
style="height: 370px"
>
<datav-tabs
type="bottom-button"
v-model="subOneProRankTab"
@ -54,14 +65,12 @@
<el-scrollbar height="280px">
<datav-chart-bar
:data="jsdwRankList"
:max="11"
size="large"
:color="colors"
/>
</el-scrollbar>
</datav-tab-item>
</datav-tabs>
</datav-card>
</el-col>
@ -110,13 +119,22 @@
ref="subOneVideoProTrend"
/>
<div class="gobal-dropdown-container">
<el-dropdown class="test" @command="handleCommand">
<span class="el-dropdown-link my-gobal-yearselect">
{{ selectedYear + ' 年' }}
<el-dropdown
class="test"
@command="handleCommand"
>
<span
class="el-dropdown-link my-gobal-yearselect"
>
{{ selectedYear + " 年" }}
</span>
<template #dropdown>
<el-dropdown-menu style="width: 90px">
<el-dropdown-item v-for="year in years" :key="year" :command="year">{{ year + " " }}
<el-dropdown-item
v-for="year in years"
:key="year"
:command="year"
>{{ year + " 年" }}
</el-dropdown-item>
</el-dropdown-menu>
</template>
@ -131,7 +149,9 @@
<div class="message message-error">
<div class="message-title">待处理</div>
<div>
芙蓉-定王台-办案区-问室 湖南省长沙市公安局芙蓉分局定王台派出所 &emsp; 民警单人询的违规问题
芙蓉-定王台-办案区-问室
湖南省长沙市公安局芙蓉分局定王台派出所
&emsp; 民警单人询的违规问题
</div>
<div class="message-footer flex between">
<span>芙蓉分局定王台派出所</span>
@ -141,7 +161,8 @@
<div class="message message-info">
<div class="message-title">待处理</div>
<div>
望城-管理中心-办案区-询问室湖南省长沙市望城区公安局法制大队&emsp; 民警单人询的违规问题
望城-管理中心-办案区-询问室湖南省长沙市望城区公安局法制大队&emsp;
民警单人询的违规问题
</div>
<div class="message-footer flex between">
<span>望城区公安局法制大队</span>
@ -151,7 +172,8 @@
<div class="message">
<div class="message-title">待处理</div>
<div>
执法办案中心-询问室7湖南省长沙市公安局芙蓉分局蓉园派出所 &emsp;同时讯问多名嫌疑对象
执法办案中心-询问室7湖南省长沙市公安局芙蓉分局蓉园派出所
&emsp;同时讯问多名嫌疑对象
</div>
<div class="message-footer flex between">
<span>芙蓉分局蓉园派出所</span>
@ -161,7 +183,8 @@
<div class="message">
<div class="message-title">待处理</div>
<div>
开福-直属-执法办案管理-讯询问室湖南省长沙市公安局开福分局法制大队 &emsp;民警单人询的违规问题
开福-直属-执法办案管理-讯询问室湖南省长沙市公安局开福分局法制大队
&emsp;民警单人询的违规问题
</div>
<div class="message-footer flex between">
<span>开福分局法制大队</span>
@ -182,7 +205,10 @@
</el-row>
</main>
</div>
<negative-info-depart-dialog v-model="showDialog" :departId="tempDepartId"/>
<negative-info-depart-dialog
v-model="showDialog"
:departId="tempDepartId"
/>
</el-scrollbar>
</template>
@ -197,8 +223,12 @@ import {
getSubOneVideoSuperviseMap,
getSubOneVideoSuperviseProblemRank,
getSubOneVideoSuperviseProblemTypeRate,
getSubOneVideoSuperviseTrend
getSubOneVideoSuperviseTrend,
} from "@/api/screen/subScreen/subOneVideoSupervise.ts";
import {
getVideoStatus,
} from "@/api/screen/videoSupervise.ts";
// region
const route = useRoute();
const currentDepartId = route.query.departId;
@ -215,21 +245,27 @@ const overview = ref({
relativePer: 0,
changedRate: 0,
});
const mapIconList = ref([{
const mapIconList = ref([
{
originalName: "浏阳市局",
name: "浏阳市",
discoverProblem: 135,
changedProblem: 135,
relativeOrg: 89,
relativePer: 152,
changedRate: 100
}])
changedRate: 100,
},
]);
const currentYear = new Date().getFullYear();
const years = ref([currentYear.toString(), (currentYear - 1).toString(), (currentYear - 2).toString()]);
const years = ref([
currentYear.toString(),
(currentYear - 1).toString(),
(currentYear - 2).toString(),
]);
const selectedYear = ref(currentYear); //
const currentMapData = ref({})
const currentMapData = ref({});
const subOneVideoMapChart = ref(null); //
const colors = [
{
@ -242,11 +278,11 @@ const colors = [
},
];
const showDialog = ref(false); //
const tempDepartId = ref(0); // id
const tempDepartId = ref('0'); // id
//
const subOneProRankTab = ref("1")
const subOneVideoProRank = ref(null)
const subOneProRankTab = ref("1");
const subOneVideoProRank = ref(null);
const subOneVideoProTrend = ref(null);
const subOneVideoProblemTypeRate = ref(null);
let subOneVideoProRankIntervalId;
@ -261,10 +297,22 @@ const proTrend = ref({
xAxis: {
type: "category",
boundaryGap: true,
data: ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月",],
data: [
"1月",
"2月",
"3月",
"4月",
"5月",
"6月",
"7月",
"8月",
"9月",
"10月",
"11月",
],
axisTick: {
// X线
show: false
show: false,
},
},
yAxis: {
@ -277,13 +325,13 @@ const proTrend = ref({
},
},
tooltip: {
trigger: 'axis',
trigger: "axis",
axisPointer: {
type: 'line',
type: "line",
label: {
backgroundColor: '#6a7985'
}
}
backgroundColor: "#6a7985",
},
},
},
series: [
{
@ -309,22 +357,23 @@ const proTrend = ref({
},
],
grid: {
left: '5%', //
right: '2%', //
top: '10%', //
bottom: '20%', //
containLabel: false //
left: "5%", //
right: "2%", //
top: "10%", //
bottom: "20%", //
containLabel: false, //
},
});
echarts.registerMap("changsha", changshaMap);
const option = ref({
tooltip: {
trigger: 'item',
position: 'bottom',
trigger: "item",
position: "bottom",
formatter: function (params) {
const dataItem = mapIconList.value.find(item => item.name === params.name) || {}; //
console.log("Data item:", dataItem);
const dataItem =
mapIconList.value.find((item) => item.name === params.name) ||
{}; //
if (dataItem.name === params.name) {
return `
<div class="tooltip">
@ -360,8 +409,14 @@ const option = ref({
bottom: 10,
pieces: [
{ gte: 0, lte: 200, label: "低于平均问题30%", color: "#4987F6" },
{gte: 200, lte: 400, label: "平均问题上下浮动30%内", color: "#F6A149"},
{gte: 400, label: "高于平均问题30%", color: "#D34343"},],
{
gte: 200,
lte: 400,
label: "平均问题上下浮动30%内",
color: "#F6A149",
},
{ gte: 400, label: "高于平均问题30%", color: "#D34343" },
],
right: 10,
realtime: false,
orient: "horizontal",
@ -388,19 +443,18 @@ const option = ref({
normal: {
areaColor: "#02215E",
borderColor: "#24D2EE",
borderWidth: 1 //
borderWidth: 1, //
},
},
emphasis: {
areaColor: "#FFD700", //
borderColor: "#FF0000", //
borderWidth: 4 //
borderWidth: 4, //
},
data: [],
}
},
],
})
});
const ProblemTypeRateChart = ref({
series: [
{
@ -418,70 +472,90 @@ const ProblemTypeRateChart = ref({
}); //
// endregion
// region
const getMapJSON = async (departId) => {
const res = await getSubOneStreetMap(departId);
currentMapData.value = res;
echarts.registerMap("changsha", res);
subOneVideoMapChart.value.chart.setOption(option.value);
}
};
const getSubOneVideoSuperviseProblemRankData = async (departId, timeValue) => {
const res = await getSubOneVideoSuperviseProblemRank(departId, timeValue);
fxsjRankList.value = res.policeVideoSuperviseProblemRankList
jsdwRankList.value = res.teamVideoSuperviseProblemRankList
}
fxsjRankList.value = res.policeVideoSuperviseProblemRankList;
jsdwRankList.value = res.teamVideoSuperviseProblemRankList;
};
const getSubOneAllVideoSuperviseCountData = async (departId, timeValue) => {
const res = await getSubOneAllVideoSuperviseCount(departId, timeValue);
overview.value = res.overview;
}
};
const getSubOneVideoSuperviseMapData = async (departId, timeValue) => {
const res = await getSubOneVideoSuperviseMap(departId, timeValue);
const mappedData = res.videoSuperviseMapIconVoList.map(item => {
const mappedData = res.videoSuperviseMapIconVoList.map((item) => {
return {
...item,
value: item.discoverProblem,
};
});
const maxItem = mappedData.reduce((max, item) => (Number(item.value) > Number(max.value) ? item : max), mappedData[0]);
const range60Percent = maxItem.value * 0.6 //
const range80Percent = maxItem.value * 0.8 //
mapIconList.value = mappedData
option.value.series[0].data = mapIconList
const maxItem = mappedData.reduce(
(max, item) => (Number(item.value) > Number(max.value) ? item : max),
mappedData[0]
);
const range60Percent = maxItem.value * 0.6; //
const range80Percent = maxItem.value * 0.8; //
mapIconList.value = mappedData;
option.value.series[0].data = mapIconList;
option.value.visualMap.pieces = [
{gte: 0, lte: range60Percent, label: "低于最大问题的60%", color: "#4987F6"},
{gte: range60Percent, lte: range80Percent, label: "介于最大问题的60%~80%", color: "#F6A149"},
{
gte: 0,
lte: range60Percent,
label: "低于最大问题的60%",
color: "#4987F6",
},
{
gte: range60Percent,
lte: range80Percent,
label: "介于最大问题的60%~80%",
color: "#F6A149",
},
{ gte: range80Percent, label: "高于最大问题80%", color: "#D34343" },
];
}
};
const getSubOneVideoSuperviseTrendData = async (departId, year) => {
const res = await getSubOneVideoSuperviseTrend(departId, year);
const temp = res.videoSuperviseTrendList;
const categories = temp.map(item => item.name);
const values = temp.map(item => item.value);
const categories = temp.map((item) => item.name);
const values = temp.map((item) => item.value);
proTrend.value.xAxis.data = categories;
proTrend.value.series[0].data = values;
}
const getSubOneVideoSuperviseProblemTypeRateData = async (departId, timeValue) => {
const res = await getSubOneVideoSuperviseProblemTypeRate(departId, timeValue);
ProblemTypeRateChart.value.series[0].data = res.subOneVideoSuperviseProblemTypeRate
}
};
const getSubOneVideoSuperviseProblemTypeRateData = async (
departId,
timeValue
) => {
const res = await getSubOneVideoSuperviseProblemTypeRate(
departId,
timeValue
);
ProblemTypeRateChart.value.series[0].data =
res.subOneVideoSuperviseProblemTypeRate;
};
const getData = async () => {
getMapJSON(currentDepartId)
getMapJSON(currentDepartId);
getSubOneVideoSuperviseProblemRankData(currentDepartId, time.value);
getSubOneAllVideoSuperviseCountData(currentDepartId, time.value);
getSubOneVideoSuperviseMapData(currentDepartId, time.value)
getSubOneVideoSuperviseTrendData(currentDepartId, selectedYear.value)
getSubOneVideoSuperviseProblemTypeRateData(currentDepartId, time.value)
}
getSubOneVideoSuperviseMapData(currentDepartId, time.value);
getSubOneVideoSuperviseTrendData(currentDepartId, selectedYear.value);
getSubOneVideoSuperviseProblemTypeRateData(currentDepartId, time.value);
};
//
const subOneVideoProRankAnimation = () => {
subOneProRankTab.value = (parseInt(subOneProRankTab.value) % 2 + 1).toString();
subOneProRankTab.value = (
(parseInt(subOneProRankTab.value) % 2) +
1
).toString();
};
subOneVideoProRankIntervalId = setInterval(subOneVideoProRankAnimation, 3000);
@ -490,7 +564,7 @@ const subOneVideoMapAnimation = () => {
const mapTemp = subOneVideoMapChart?.value?.chart;
if (!mapTemp) return;
// 0
const tempNum = currentMapData?.value?.geoJson?.features?.length
const tempNum = currentMapData?.value?.geoJson?.features?.length;
const randomNum = Math.floor(Math.random() * tempNum);
mapTemp.dispatchAction({
type: "downplay", //downplay
@ -515,11 +589,11 @@ const subOneVideoTrendAnimation = () => {
if (!trendTemp) return;
const randomNum = Math.floor(Math.random() * 12);
trendTemp.dispatchAction({
type: 'showTip',
type: "showTip",
seriesIndex: 0,
dataIndex: randomNum,
});
}
};
subOneVideoTrendIntervalId = setInterval(subOneVideoTrendAnimation, 2000);
//
const subOneVideoProblemTypeRateAnimation = () => {
@ -527,82 +601,115 @@ const subOneVideoProblemTypeRateAnimation = () => {
if (!temp) return;
const length = ProblemTypeRateChart.value.series[0].data.length;
const randomNum = Math.floor(Math.random() * length);
temp?.dispatchAction({type: 'downplay', seriesIndex: 0});
temp?.dispatchAction({type: 'highlight', seriesIndex: 0, dataIndex: randomNum}); //
temp?.dispatchAction({type: 'showTip', seriesIndex: 0, dataIndex: randomNum});
}
subOneVideoProblemTypeRateIntervalId = setInterval(subOneVideoProblemTypeRateAnimation, 2000);
temp?.dispatchAction({ type: "downplay", seriesIndex: 0 });
temp?.dispatchAction({
type: "highlight",
seriesIndex: 0,
dataIndex: randomNum,
}); //
temp?.dispatchAction({
type: "showTip",
seriesIndex: 0,
dataIndex: randomNum,
});
};
subOneVideoProblemTypeRateIntervalId = setInterval(
subOneVideoProblemTypeRateAnimation,
2000
);
onMounted(() => {
getData();
setupEventListeners(); //
})
});
// endregion
// region ||
watch(time, () => {
getData()
})
getData();
});
const handleCommand = (year) => {
selectedYear.value = year; //
getSubOneVideoSuperviseTrendData(currentDepartId, selectedYear.value)
getSubOneVideoSuperviseTrendData(currentDepartId, selectedYear.value);
};
const subOneVideoProRankAnimationStop = () => {
const temp = subOneVideoProRank.value?.$el;
temp.addEventListener('mouseenter', () => {
clearInterval(subOneVideoProRankIntervalId)
temp.addEventListener("mouseenter", () => {
clearInterval(subOneVideoProRankIntervalId);
});
temp.addEventListener('mouseleave', () => {
temp.addEventListener("mouseleave", () => {
subOneVideoProRankIntervalId = setTimeout(() => {
subOneVideoProRankAnimation();
}, 3000);
});
}
};
const subOneVideoMapAnimationStop = () => {
const temp = subOneVideoMapChart?.value?.chart;
//
temp.on('mousemove', (e) => {
temp.on("mousemove", (e) => {
clearInterval(subOneVideoMapIntervalId);
temp.dispatchAction({type: "downplay", seriesIndex: 0,});
temp.dispatchAction({type: "highlight", seriesIndex: 0, dataIndex: e.dataIndex,});
temp.dispatchAction({type: "showTip", seriesIndex: 0, dataIndex: e.dataIndex,});
temp.dispatchAction({ type: "downplay", seriesIndex: 0 });
temp.dispatchAction({
type: "highlight",
seriesIndex: 0,
dataIndex: e.dataIndex,
});
temp.dispatchAction({
type: "showTip",
seriesIndex: 0,
dataIndex: e.dataIndex,
});
});
//
temp.on('mouseout', () => {
temp.on("mouseout", () => {
if (showDialog.value) {
clearInterval(subOneVideoMapIntervalId); //
} else {
clearInterval(subOneVideoMapIntervalId); //
subOneVideoMapIntervalId = setInterval(subOneVideoMapAnimation, 2000);
subOneVideoMapIntervalId = setInterval(
subOneVideoMapAnimation,
2000
);
}
});
}
};
const subOneVideoTrendAnimationStop = () => {
const temp = subOneVideoProTrend?.value.getDom();
temp.addEventListener('mouseenter', () => {
temp.addEventListener("mouseenter", () => {
clearInterval(subOneVideoTrendIntervalId);
});
temp.addEventListener('mouseleave', () => {
temp.addEventListener("mouseleave", () => {
clearInterval(subOneVideoTrendIntervalId);
subOneVideoTrendIntervalId = setInterval(subOneVideoTrendAnimation, 2000);
subOneVideoTrendIntervalId = setInterval(
subOneVideoTrendAnimation,
2000
);
});
}
};
const subOneVideoProblemTypeRateAnimationStop = () => {
const temp = subOneVideoProblemTypeRate?.value?.chart;
temp.on('mousemove', (e) => {
temp.on("mousemove", (e) => {
clearInterval(subOneVideoProblemTypeRateIntervalId);
temp.dispatchAction({type: "downplay", seriesIndex: 0,});
temp.dispatchAction({type: "highlight", seriesIndex: 0, dataIndex: e.dataIndex,});
temp.dispatchAction({type: "showTip", seriesIndex: 0, dataIndex: e.dataIndex,});
})
temp.on('mouseout', () => {
temp.dispatchAction({ type: "downplay", seriesIndex: 0 });
temp.dispatchAction({
type: "highlight",
seriesIndex: 0,
dataIndex: e.dataIndex,
});
temp.dispatchAction({
type: "showTip",
seriesIndex: 0,
dataIndex: e.dataIndex,
});
});
temp.on("mouseout", () => {
clearInterval(subOneVideoProblemTypeRateIntervalId);
subOneVideoProblemTypeRateIntervalId = setInterval(subOneVideoProblemTypeRateAnimation, 2000);
})
}
subOneVideoProblemTypeRateIntervalId = setInterval(
subOneVideoProblemTypeRateAnimation,
2000
);
});
};
//
const setupEventListeners = () => {
subOneVideoProRankAnimationStop();
@ -614,11 +721,37 @@ const setupEventListeners = () => {
const handleClick = (params) => {
const departId = params.data.departId;
showDialog.value = true;
tempDepartId.value = departId
tempDepartId.value = departId;
clearInterval(subOneVideoMapIntervalId);
}
};
// endregion
import { listVideoConfigByDepartId } from '@/api/system/videoConfig'
const videos = ref([]);
const activeUrl = ref('');
const videoStatus = ref({
all: 0,
percentage: "0%",
on: 0,
});
onMounted(() => {
getVideoStatus().then((data) => {
videoStatus.value = data;
});
listVideoConfigByDepartId(route.query.departId).then(data => {
videos.value = data;
if (data.length > 0) {
activeUrl.value = data[0].videoUrl
}
})
});
const activeVideoIndex = ref(0);
function handlePlay(item, index) {
activeVideoIndex.value = index;
activeUrl.value = item.videoUrl;
}
</script>
@ -648,7 +781,8 @@ img {
180deg,
rgba(255, 255, 255, 0.28),
rgba(255, 255, 255, 0.26)
) 1 1;
)
1 1;
&.message-error {
background: linear-gradient(
@ -661,7 +795,8 @@ img {
180deg,
rgba(255, 71, 71, 0.59),
rgba(251, 95, 95, 1)
) 1 1;
)
1 1;
.message-title {
color: #ff0017;
@ -679,7 +814,8 @@ img {
180deg,
rgba(71, 209, 255, 0.28),
rgba(8, 177, 255, 1)
) 1 1;
)
1 1;
.message-title {
color: #1cd9ff;
@ -700,15 +836,18 @@ img {
}
}
:deep() {
//
.tooltip {
position: relative;
width: 169.88px;
height: 178px;
background: linear-gradient(180deg, rgba(1, 4, 87, 0.8) 0%, rgba(3, 21, 119, 0.8) 100%);
border: 1px solid #4E8FFF;
background: linear-gradient(
180deg,
rgba(1, 4, 87, 0.8) 0%,
rgba(3, 21, 119, 0.8) 100%
);
border: 1px solid #4e8fff;
margin: -10px -10px -10px -10px;
}
@ -716,19 +855,22 @@ img {
.tooltip-title {
width: 169.88px;
height: 43px;
background: linear-gradient(180deg, rgba(1, 4, 87, 0.8) 0%, rgba(3, 21, 119, 0.8) 100%);
background: linear-gradient(
180deg,
rgba(1, 4, 87, 0.8) 0%,
rgba(3, 21, 119, 0.8) 100%
);
display: flex;
justify-content: center; /* 水平居中 */
align-items: center; /* 垂直居中 */
text-align: center; /* 水平居中 */
font-weight: 400;
font-size: 16px;
color: #FFFFFF;
color: #ffffff;
line-height: 22px;
border-bottom: 1px solid #253755; /* 设置下边框 */
}
.tooltip-content {
width: 170px;
height: 132px;
@ -740,17 +882,15 @@ img {
.tooltip-content ul {
list-style-type: none; /* 移除默认的小圆点 */
padding: 0;
}
.tooltip-content ul li {
margin-left: 5px;
height: 25px;
color: #597AE9;
color: #597ae9;
font-size: 13px;
}
// span
.tooltip-ul span {
float: right;
@ -761,10 +901,9 @@ img {
font-size: 13px;
}
/* 小尖角 */
.tooltip::before {
content: '';
content: "";
position: absolute;
top: 90px; /* 调整尖角的垂直位置 */
left: -10px; /* 调整尖角的水平位置 */
@ -774,11 +913,8 @@ img {
//border-bottom: 10px solid green; /* */
//border-right: 10px solid blue; /* */
}
}
.gobal-dropdown-container {
position: absolute;
right: 20px;
@ -788,7 +924,7 @@ img {
.test {
width: 95px;
height: 25px;
background: #1C3472;
background: #1c3472;
}
.gobal-dropdown-container {
@ -804,6 +940,4 @@ img {
width: 90px;
color: #fff;
}
</style>

13
src/views/rightsComfort/Comfort.vue

@ -30,6 +30,18 @@
<depart-tree-select v-model="query.departId" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="状态">
<el-select v-model="query.rpcStatus">
<el-option
v-for="item in dict.comfortStatus"
:key="item.id"
:label="item.dictLabel"
:value="item.dictValue"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div class="flex end">
@ -67,6 +79,7 @@
width="100"
/>
<el-table-column label="申请人单位" prop="departName" />
<el-table-column label="主办单位" prop="handleDepartName" />
<el-table-column label="开户行">
<template #default="{ row }">
<span>{{ row.bankCard }}</span>

445
src/views/rightsComfort/ComfortPacks.vue

@ -0,0 +1,445 @@
<template>
<div class="container">
<header class="mb-20">
<el-form :label-width="114">
<el-row>
<el-col :span="6">
<el-form-item label="呈报时间">
<date-time-range-picker-ext
v-model="query.reportTime"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="呈报说明">
<el-input
v-model="query.reportTitle"
placeholder="请输入"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div class="flex between">
<el-button type="primary" @click="handleAdd">
<template #icon>
<icon name="el-icon-Plus" />
</template>
新增抚慰金呈报</el-button
>
<div>
<el-button type="primary" @click="getList">
<template #icon>
<icon name="el-icon-Search" />
</template>
查询</el-button
>
<el-button @click="reset">重置</el-button>
</div>
</div>
</header>
<div class="table-container">
<el-table :data="list">
<el-table-column
label="呈报说明"
prop="reportTitle"
show-overflow-tooltip
/>
<el-table-column
label="呈报人数"
prop="reportNum"
align="center"
/>
<el-table-column label="呈报金额" prop="reportMoney" />
<el-table-column label="呈报时间" prop="reportTime" />
<el-table-column label="操作" width="200">
<template #default="{ row }">
<el-button
link
type="primary"
@click="handleShowDetail(row)"
>查看</el-button
>
<el-button link type="primary" @click="download(row)"
>下载呈报件</el-button
>
</template>
</el-table-column>
</el-table>
</div>
<div class="flex end mt-8">
<el-pagination
@size-change="getList"
@current-change="getList"
:page-sizes="[10, 20, 50]"
v-model:page-size="query.size"
v-model:current-page="query.current"
layout="total, sizes, prev, pager, next"
:total="total"
>
</el-pagination>
</div>
</div>
<el-dialog
v-model="show"
title="新增抚慰金呈报"
width="70vw"
top="3vh"
style="margin-bottom: 0"
>
<el-table
:data="comforts"
style="height: 500px"
ref="comfortTableRef"
@selection-change="handleSelectionChange"
>
<el-table-column
type="selection"
:reserve-selection="false"
width="55"
/>
<el-table-column
label="抚慰编号"
prop="number"
show-overflow-tooltip
/>
<el-table-column label="申请时间" prop="applyDate" width="160" />
<el-table-column label="事发时间" prop="happenTime" width="160" />
<el-table-column
label="申请人姓名"
prop="applicantEmpName"
width="100"
/>
<el-table-column label="申请人单位" prop="departName" />
<el-table-column
label="受伤程度"
prop="injurySeverityName"
width="120"
/>
<el-table-column
label="抚慰金额"
prop="injurySeverity"
width="100"
align="center"
>
<template #default="{ row }">
<span v-if="row.injurySeverity"
>{{ row.injurySeverity }}</span
>
</template>
</el-table-column>
<el-table-column label="状态" width="100">
<template #default="{ row }">
<el-tag type="primary">{{
getDictLable(dict.comfortStatus, row.rpcStatus)
}}</el-tag>
</template>
</el-table-column>
</el-table>
<div class="flex end mt-8 mb-20">
<el-pagination
@size-change="getComfort"
@current-change="getComfort"
:page-sizes="[10, 20, 50]"
v-model:page-size="comfortQuery.size"
v-model:current-page="comfortQuery.current"
layout="total, sizes, prev, pager, next"
:total="comfortTotal"
>
</el-pagination>
</div>
<el-form label-width="160" ref="formRef" :model="formData">
<el-form-item
label="呈报人数"
prop="comforts"
:rules="{
required: true,
validator: validateComforts,
}"
>
<span>{{ formData.comforts.length }}</span>
</el-form-item>
<el-form-item label="呈报金额">
{{
formData.comforts.length > 0
? formData.comforts
.map((item) => parseInt(item.injurySeverity))
.reduce((a, b) => a + b, 0)
: 0
}}
</el-form-item>
<el-form-item
label="呈报说明"
prop="reportTitle"
:rules="{
required: true,
message: '请输入呈报说明',
}"
>
<el-input
type="textarea"
v-model="formData.reportTitle"
clearable
/>
</el-form-item>
</el-form>
<footer class="flex end mt-20">
<el-button size="large">取消</el-button>
<el-button
type="primary"
size="large"
@click="handleSubmit"
:disabled="disabled"
>提交呈报</el-button
>
</footer>
</el-dialog>
<el-dialog
v-model="detailShow"
title="抚慰金呈报详情"
width="70vw"
top="3vh"
style="margin-bottom: 0"
>
<div style="min-height: 500px">
<div class="table-container mb-40">
<el-table
:data="comfortPack.comforts"
style="max-height: 500px"
>
<el-table-column
label="抚慰编号"
prop="number"
show-overflow-tooltip
/>
<el-table-column
label="申请时间"
prop="applyDate"
width="160"
/>
<el-table-column
label="事发时间"
prop="happenTime"
width="160"
/>
<el-table-column
label="申请人姓名"
prop="applicantEmpName"
width="100"
/>
<el-table-column label="申请人单位" prop="departName" />
<el-table-column
label="受伤程度"
prop="injurySeverityName"
width="120"
/>
<el-table-column
label="抚慰金额"
prop="injurySeverity"
width="100"
align="center"
>
<template #default="{ row }">
<span v-if="row.injurySeverity"
>{{ row.injurySeverity }}</span
>
</template>
</el-table-column>
<el-table-column
label="操作"
width="100"
>
<template #default="{ row }">
<el-button
link
type="primary"
@click="handleComfortShow(row)"
>查看</el-button
>
</template>
</el-table-column>
</el-table>
</div>
<div class="row">
<div class="col col-12">
<label>呈报人数</label>
<span>{{ comfortPack.reportNum }}</span>
</div>
<div class="col col-12">
<label>呈报金额</label>
<span>{{ comfortPack.reportMoney }}</span>
</div>
<div class="col col-24">
<label>呈报说明</label>
<span>{{ comfortPack.reportTitle }}</span>
</div>
</div>
</div>
</el-dialog>
<comfort-dialog v-model:show="actionShow" :id="activeRpcId" />
</template>
<script setup>
import { BASE_PATH } from "@/api/request";
import moment from "moment";
import {
listComfortPacks,
addComfortPacks,
getComfortPacks,
} from "@/api/rightsComfort/comfortPacks";
import { listComfort } from "@/api/rightsComfort/comfort";
import { listPolice } from "@/api/system/police";
import { getDictLable } from "@/utils/util";
import feedback from "@/utils/feedback";
import useCatchStore from "@/stores/modules/catch";
import { nextTick } from "vue";
const catchStore = useCatchStore();
const dict = catchStore.getDicts(["comfortStatus"]);
const list = ref([]);
const query = ref({
current: 1,
size: 10,
});
const total = ref(0);
function getList() {
listComfortPacks(query.value).then((data) => {
list.value = data.records;
total.value = data.total;
});
}
function reset() {
query.value = {
current: 1,
size: 10,
};
getList();
}
getList();
const actionShow = ref(false);
const activeRpcId = ref('');
async function handleComfortShow(row) {
actionShow.value = true;
activeRpcId.value = row.rpcId;
}
const show = ref(false);
const comforts = ref([]);
const comfortQuery = ref({
current: 1,
size: 10,
rpcStatus: "to_be_reported",
});
const comfortTableRef = ref();
const comfortTotal = ref(0);
async function handleAdd() {
show.value = true;
await getComfort();
}
let lock = false;
async function getComfort() {
const data = await listComfort(comfortQuery.value);
comforts.value = data.records;
comfortTotal.value = data.total;
nextTick(() => {
lock = true;
comforts.value.forEach((item) => {
if (formData.value.comforts.some((o) => o.rpcId === item.rpcId)) {
comfortTableRef.value.toggleRowSelection(item, true);
}
});
lock = false;
});
}
const formRef = ref();
const formData = ref({
comforts: [],
});
function handleSelectionChange(selection) {
if (lock) {
return;
}
selection.forEach((item) => {
if (!formData.value.comforts.some((o) => o.rpcId === item.rpcId)) {
formData.value.comforts.push(item);
}
});
comforts.value
.filter((item) => !selection.some((o) => o.rpcId === item.rpcId))
.forEach((item) => {
const obj = formData.value.comforts.find(
(o) => o.rpcId === item.rpcId
);
if (obj) {
formData.value.comforts.splice(
formData.value.comforts.indexOf(obj),
1
);
}
});
}
function validateComforts(rule, value, cb) {
if (value.length === 0) {
cb(new Error("请选择呈报人"));
} else {
cb();
}
}
const disabled = ref(false);
async function handleSubmit() {
await formRef.value.validate();
disabled.value = true;
try {
await addComfortPacks(formData.value);
} catch (e) {
disabled.value = false;
return;
}
disabled.value = false;
formData.value = {
comforts: [],
};
show.value = false;
getList();
feedback.msgSuccess("操作成功");
}
function download(row) {
window.open(`${BASE_PATH}/file/stream/${row.reportZip}`);
}
const detailShow = ref(false);
const comfortPack = ref({
comforts: [],
});
const detailLoading = ref(false);
async function handleShowDetail(row) {
detailShow.value = true;
detailLoading.value = true;
comfortPack.value = await getComfortPacks(row.id);
detailLoading.value = false;
}
</script>
<style lang="scss" scoped>
h5 {
margin: 10px 0;
}
</style>

492
src/views/rightsComfort/MyComfort.vue

@ -83,12 +83,20 @@
</el-table-column>
<el-table-column label="状态" width="100">
<template #default="{ row }">
<el-tag type="primary" v-if="row.rpcStatus">{{
<el-tag
:type="
row.rpcStatus !== 'returned'
? 'primary'
: 'danger'
"
v-if="row.rpcStatus"
>{{
getDictLable(
dict.comfortStatus,
row.rpcStatus
)
}}</el-tag>
}}</el-tag
>
</template>
</el-table-column>
<el-table-column label="操作" width="200">
@ -97,8 +105,30 @@
link
type="primary"
@click="handleShow(row, false)"
v-if="row.rpcStatus !== 'returned'"
>立即处理</el-button
>
<template v-else>
<el-button
link
type="primary"
@click="handleShow(row, true)"
>查看</el-button
>
<el-button
link
type="primary"
@click="handleReSubmit(row)"
>重新提交</el-button
>
<el-button
link
type="danger"
v-if="row.rpcStatus === 'returned'"
@click="handleDelete(row)"
>删除</el-button
>
</template>
</template>
</el-table-column>
</el-table>
@ -154,7 +184,12 @@
</el-table-column>
<el-table-column label="操作" width="200">
<template #default="{ row }">
<el-button link type="primary" @click="handleShow(row, true)">查看</el-button>
<el-button
link
type="primary"
@click="handleShow(row, true)"
>查看</el-button
>
</template>
</el-table-column>
</el-table>
@ -182,8 +217,13 @@
top="2vh"
style="margin-bottom: 0"
>
<el-scrollbar max-height="calc(96vh - 130px)">
<el-form :label-width="140" ref="formRef" :model="formData">
<el-scrollbar height="calc(96vh - 130px)">
<el-form
:label-width="140"
ref="formRef"
:model="formData"
v-if="step === 0"
>
<h5>办理信息</h5>
<el-row>
<el-col :span="12">
@ -215,9 +255,14 @@
prop="handleDepartId"
>
<div style="width: 300px">
<depart-tree-select
<el-tree-select
v-model="formData.handleDepartId"
:check-strictly="true"
:data="departs"
:props="{ label: 'shortName', value: 'id' }"
node-key="id"
:default-expanded-keys="['12630']"
clearable
filterable
@node-click="
(node) =>
(formData.handleDepartName =
@ -239,9 +284,12 @@
}"
prop=""
>
<el-radio-group v-model="formData.isSelf">
<el-radio :value="1"></el-radio>
<el-radio :value="0"></el-radio>
<el-radio-group
v-model="formData.isSelf"
@change="handleSelectIsSelf"
>
<el-radio value="1"></el-radio>
<el-radio value="0"></el-radio>
</el-radio-group>
</el-form-item>
</el-col>
@ -261,43 +309,22 @@
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12" v-if="formData.isSelf === 0">
<el-col :span="12" v-if="formData.isSelf === '0'">
<el-form-item
label="代理人姓名"
:rules="{
required: true,
trigger: ['blur'],
message: '请输入代理人姓名',
}"
prop=""
prop="agentName"
>
<el-input
style="width: 300px"
v-model="formData.agentName"
placeholder="请输入"
/>
</el-form-item>
</el-col>
<el-col :span="12" v-if="formData.isSelf === 0">
<el-form-item
label="代理人单位"
:rules="{
required: true,
trigger: ['blur'],
}"
prop=""
>
<div style="width: 300px">
<depart-tree-select
v-model="formData.handleDepartId"
:check-strictly="true"
@node-click="
(node) =>
(formData.handleDepartName =
node.shortName)
"
/>
</div>
</el-form-item>
</el-col>
</el-row>
<h5>申请人信息</h5>
<el-row>
@ -362,6 +389,82 @@
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
label="身份证号码"
:rules="{
required: true,
message: '请输入',
}"
prop="idCode"
>
<el-input
v-model="formData.idCode"
clearable
style="width: 300px"
placeholder="请输入"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
label="单位"
:rules="{
required: true,
message: '请选择',
}"
prop="departId"
>
<div style="width: 300px">
<depart-tree-select
v-model="formData.departId"
:check-strictly="true"
@node-click="
(node) =>
(formData.departName =
node.shortName)
"
/>
</div>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
label="警号"
:rules="{
required: true,
message: '请输入',
}"
prop="empNo"
>
<el-input
v-model="formData.empNo"
style="width: 300px"
placeholder="请输入"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="职务" prop="job">
<el-input
v-model="formData.job"
style="width: 300px"
placeholder="请输入"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="警衔" prop="policeRank">
<el-input
v-model="formData.policeRank"
style="width: 300px"
placeholder="请输入"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
label="文化程度"
@ -407,106 +510,54 @@
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
label="身份证号码"
:rules="{
required: true,
message: '请输入',
}"
prop="idCode"
>
<el-input
v-model="formData.idCode"
clearable
style="width: 300px"
placeholder="请输入"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
<el-form-item-ext
label="联系电话"
:rules="{
required: true,
message: '请输入',
}"
prop="mobile"
content="银行预留电话"
>
<el-input
v-model="formData.mobile"
style="width: 300px"
placeholder="请输入"
placeholder="请输入银行预留电话"
/>
</el-form-item>
</el-form-item-ext>
</el-col>
<el-col :span="12">
<el-form-item
label="单位"
label="开户行"
prop="bankCard"
:rules="{
required: true,
message: '请选择',
}"
prop="departId"
>
<div style="width: 300px">
<depart-tree-select
v-model="formData.departId"
:check-strictly="true"
@node-click="
(node) =>
(formData.departName =
node.shortName)
"
/>
</div>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="职务" prop="job">
<el-input
v-model="formData.job"
<el-select
v-model="formData.bankCard"
clearable
style="width: 300px"
placeholder="请输入"
>
<el-option
v-for="item in dict.bank"
:key="item.id"
:label="item.dictLabel"
:value="item.dictValue"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
label="警号"
label="所属支行"
prop="bankBranch"
:rules="{
required: true,
message: '请输入',
}"
prop="empNo"
>
<el-input
v-model="formData.empNo"
style="width: 300px"
placeholder="请输入"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="警衔" prop="policeRank">
<el-input
v-model="formData.policeRank"
style="width: 300px"
placeholder="请输入"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="开户行" prop="bankCard">
<el-input
v-model="formData.bankCard"
style="width: 300px"
placeholder="请输入"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="所属支行" prop="bankBranch">
<el-input
v-model="formData.bankBranch"
style="width: 300px"
@ -515,7 +566,14 @@
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="银行账号" prop="bankCardAccount">
<el-form-item
label="银行账号"
prop="bankCardAccount"
:rules="{
required: true,
message: '请输入',
}"
>
<el-input
v-model="formData.bankCardAccount"
style="width: 300px"
@ -653,20 +711,6 @@
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
label="办案单位"
prop=""
:rules="{
required: true,
message: '请选择',
}"
>
<div style="width: 300px">
<depart-tree-select :check-strictly="true" />
</div>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
label="侵权人姓名"
@ -702,13 +746,12 @@
</el-row>
<el-divider />
<h5>佐证材料</h5>
<el-row>
<el-col :span="12">
<el-form-item label="附件" prop="documentFile">
<file-upload v-model:files="formData.documentFile" />
<file-upload
v-model:files="formData.documentFile"
tips="1、事情经过(盖章)。2、受伤照片。3、伤情鉴定。4、受立案登记表。5、其他。"
/>
</el-form-item>
</el-col>
</el-row>
<el-divider />
<h5>呈报审批</h5>
<el-row>
@ -727,27 +770,53 @@
</el-col>
</el-row>
</el-form>
<div v-else style="height: 60vh" class="flex center">
<el-result
icon="success"
title="申请成功"
sub-title="请在我的已办查看进度"
>
</el-result>
</div>
</el-scrollbar>
<footer class="flex end">
<footer class="flex end" v-if="step === 0">
<el-button @click="show = false" size="large">取消</el-button>
<el-button type="primary" @click="submit" size="large"
<el-button
type="primary"
@click="submit"
size="large"
:disabled="btDisabled"
>确定</el-button
>
</footer>
</el-dialog>
<comfort-dialog v-model:show="actionShow" :id="activeRpcId" :disabled="dialogDisabled" />
<comfort-dialog
v-model:show="actionShow"
:id="activeRpcId"
:disabled="dialogDisabled"
@update="search()"
/>
</template>
<script setup>
import moment from "moment";
import { listTodos, listDone, applyComfort } from "@/api/rightsComfort/comfort";
import {
listComfortTodos,
listDone,
applyComfort,
updateComfort,
delComfort,
getDetail,
} from "@/api/rightsComfort/comfort";
import { listPolice } from "@/api/system/police";
import { listRightPersonByDepartId } from "@/api/system/rightPerson";
import { getDictLable } from "@/utils/util";
import { secondList } from "@/api/system/depart";
import { getDictLable, getGenderFromIdCode } from "@/utils/util";
import feedback from "@/utils/feedback";
import useCatchStore from "@/stores/modules/catch";
import { onMounted } from "vue";
import useUserStore from "@/stores/modules/user";
const catchStore = useCatchStore();
const dict = catchStore.getDicts([
@ -755,11 +824,10 @@ const dict = catchStore.getDicts([
"injurySeverity",
"incidentLink",
"comfortStatus",
"bank",
]);
const query = ref({
});
const query = ref({});
const todos = ref([]);
const todoPage = reactive({
@ -768,7 +836,7 @@ const todoPage = reactive({
size: 10,
});
const dones = ref([])
const dones = ref([]);
const donePage = reactive({
total: 0,
current: 1,
@ -776,19 +844,19 @@ const donePage = reactive({
});
function getTodos() {
const queryParam = {...query.value}
queryParam.current = todoPage.current
queryParam.size = todoPage.size
listTodos(queryParam).then((data) => {
const queryParam = { ...query.value };
queryParam.current = todoPage.current;
queryParam.size = todoPage.size;
listComfortTodos(queryParam).then((data) => {
todos.value = data.records;
todoPage.total = data.total;
});
}
function getDones() {
const queryParam = {...query.value}
queryParam.current = donePage.current
queryParam.size = donePage.size
const queryParam = { ...query.value };
queryParam.current = donePage.current;
queryParam.size = donePage.size;
listDone(queryParam).then((data) => {
dones.value = data.records;
donePage.total = data.total;
@ -801,18 +869,22 @@ function reset() {
size: 10,
};
getTodos();
getDones()
getDones();
}
function search() {
getTodos()
getDones()
getTodos();
getDones();
}
const departs = ref([]);
onMounted(() => {
getTodos();
getDones()
})
getDones();
secondList().then((data) => {
departs.value = data;
});
});
const show = ref(false);
const formData = ref({
@ -820,22 +892,83 @@ const formData = ref({
});
const formRef = ref(null);
function submit() {
formRef.value.validate((flag) => {
if (flag) {
applyComfort(formData.value).then(() => {
feedback.msgSuccess("操作成功");
const btDisabled = ref(false);
const step = ref(0);
async function submit() {
try {
await formRef.value.validate();
} catch (e) {
feedback.msgWarning("请检查输入项");
return;
}
btDisabled.value = true;
if (mode.value === "add") {
await applyComfort(formData.value);
} else {
updateComfort(formData.value);
getTodos();
}
step.value = 1;
show.value = false;
formData.value = {
applyDate: moment().format("YYYY-MM-DD"),
};
getDones()
});
}
});
getDones();
btDisabled.value = false;
formRef.value.resetFields();
}
const mode = ref("add");
function handleShowAdd() {
step.value = 0;
mode.value = "add";
show.value = true;
}
async function handleReSubmit(row) {
const data = await getDetail(row.rpcId);
formData.value = {
rpcId: data.apply.rpcId,
applyDate: data.apply.applyDate,
happenTime: data.apply.happenTime,
applicantEmpName: data.apply.applicantEmpName,
handleDepartId: data.apply.handleDepartId,
handleDepartName: data.apply.handleDepartName,
isSelf: data.apply.isSelf,
relation: data.apply.relation,
agentName: data.apply.agentName,
departId: data.apply.departId,
departName: data.apply.departName,
happenTime: data.apply.happenTime,
factReason: data.apply.factReason,
incidentLink: data.apply.incidentLink,
incidentLinkName: data.apply.incidentLinkName,
formsOfTort: data.apply.formsOfTort,
formsOfTortName: data.apply.formsOfTortName,
infringerName: data.apply.infringerName,
infringerHandle: data.apply.infringerHandle,
documentFile: data.apply.documentFile
? JSON.parse(data.apply.documentFile)
: [],
sex: data.person.sex,
birthday: data.person.birthday,
idCode: data.person.idCode,
empNo: data.person.empNo,
job: data.person.job,
policeRank: data.person.policeRank,
politicCountenance: data.person.politicCountenance,
mobile: data.person.mobile,
bankCard: data.person.bankCard,
bankBranch: data.person.bankBranch,
bankCardAccount: data.person.bankCardAccount,
levelEducation: data.person.levelEducation,
injurySeverity: data.applyPerson.injurySeverity,
injurySeverityName: data.applyPerson.injurySeverityName,
};
mode.value = "edit";
show.value = true;
}
@ -862,8 +995,10 @@ watch(
(val) => {
listRightPersonByDepartId(val).then((data) => {
if (data.length) {
formData.value.approverEmpNo = data.map(item => item.empNo)
formData.value.approver = data.map(item => item.empName).join('、')
formData.value.approverEmpNo = data.map((item) => item.empNo);
formData.value.approver = data
.map((item) => item.empName)
.join("、");
} else {
delete formData.value.approverEmpNo;
delete formData.value.approver;
@ -873,19 +1008,46 @@ watch(
);
const actionShow = ref(false);
const activeRpcId = ref(false)
const dialogDisabled = ref(true)
const activeRpcId = ref(false);
const dialogDisabled = ref(true);
function handleShow(row, disabled) {
actionShow.value = true
activeRpcId.value = row.rpcId
dialogDisabled.value = disabled
actionShow.value = true;
activeRpcId.value = row.rpcId;
dialogDisabled.value = disabled;
}
const handleDelete = async (row) => {
await feedback.confirm(`确定要删除 ${row.number}`);
await delComfort(row.rpcId);
feedback.msgSuccess("删除成功");
getTodos();
};
const userStore = useUserStore();
function handleSelectIsSelf() {
if (formData.value.isSelf === "1") {
formData.value.applicantEmpName = userStore.user.nickName;
formData.value.idCode = userStore.user.userName;
formData.value.empNo = userStore.user.empNo;
formData.value.mobile = userStore.user.mobile;
formData.value.departId = userStore.user.departId;
const sex = getGenderFromIdCode(formData.value.idCode);
if (sex) {
formData.value.sex = sex === "男" ? 0 : 1;
}
if (formData.value.idCode && formData.value.idCode.length === 18) {
formData.value.birthday = moment(
formData.value.idCode.substring(6, 14),
"YYYYMMDD"
).format("YYYY-MM-DD");
}
}
}
const resultShow = ref(true);
</script>
<style lang="scss" scoped>
h5 {
margin: 10px 0;
}
</style>

82
src/views/rightsComfort/Rights.vue

@ -47,29 +47,28 @@
<div class="table-container">
<el-table :data="list">
<el-table-column
label="维权编号"
prop="number"
show-overflow-tooltip
label="申请人姓名"
prop="applicantEmpName"
width="100"
/>
<el-table-column
label="申请时间"
prop="applyDate"
width="160"
label="申请人警号"
prop="applicantEmpNo"
width="100"
/>
<el-table-column
label="事发时间"
prop="happenTime"
width="160"
/>
<el-table-column
label="申请人姓名"
prop="applicantEmpName"
width="100"
/>
<el-table-column label="申请人单位" prop="departName" />
<el-table-column label="申请人单位" prop="departName" width="180" show-overflow-tooltip />
<el-table-column label="案件编号" prop="caseNumber" width="200" />
<el-table-column label="案件经过" prop="factReason" show-overflow-tooltip />
<el-table-column label="状态" width="100">
<template #default="{ row }">
<el-tag type="primary">{{
getDictLable(dict.comfortStatus, row.rpcStatus)
}}</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="200">
@ -77,13 +76,13 @@
<el-button
link
type="primary"
@click="handleShow(row)"
@click="handleDetail(row)"
>查看</el-button
>
<el-button
link
type="danger"
@click="handleShow(row)"
@click="handleDelete(row)"
>删除</el-button
>
</template>
@ -104,10 +103,49 @@
</div>
</div>
<el-dialog title="维权详情" v-model="show" width="50vw">
<div class="dialog-container">
<div class="row mt-10">
<div class="col col-12">
<label>申请人姓名</label>
<span>{{ activeRow.applicantEmpName }}</span>
</div>
<div class="col col-12">
<label>申请人警号</label>
<span>{{ activeRow.applicantEmpNo }}</span>
</div>
<div class="col col-12">
<label>事发时间</label>
<span>{{ activeRow.happenTime }}</span>
</div>
<div class="col col-12">
<label>案件编号</label>
<span>{{ activeRow.caseNumber || '/' }}</span>
</div>
<div class="col col-12">
<label>状态</label>
<span>{{
getDictLable(
dict.comfortStatus,
activeRow.rpcStatus
)
}}</span>
</div>
</div>
<div class="row mt-10" style="margin-bottom: 60px">
<div class="col col-24">
<label>案件经过</label>
<span>{{ activeRow.factReason }}</span>
</div>
</div>
</div>
</el-dialog>
</template>
<script setup>
import moment from "moment";
import { listRights } from "@/api/rightsComfort/rights";
import { delComfort } from "@/api/rightsComfort/comfort";
import { listPolice } from "@/api/system/police";
import { getDictLable } from "@/utils/util";
import feedback from "@/utils/feedback";
@ -116,9 +154,6 @@ import useCatchStore from "@/stores/modules/catch";
const catchStore = useCatchStore();
const dict = catchStore.getDicts([
"formsOfTort",
"injurySeverity",
"incidentLink",
"comfortStatus"
]);
@ -154,11 +189,18 @@ function handleShow(row) {
}
const handleDelete = async (row) => {
await feedback.confirm(`确定要删除 ${row.number}`);
// await delComfort(row.rpcId);
await feedback.confirm(`确定要删除该数据`);
await delComfort(row.rpcId);
feedback.msgSuccess("删除成功");
getList();
};
const activeRow = ref({})
const show = ref(false)
const handleDetail = (row) => {
activeRow.value = row
show.value = true
};
</script>
<style lang="scss" scoped>
h5 {

4
src/views/sensitivePerception/Model.vue

@ -837,11 +837,11 @@
"
>
<el-form-item
label="通知单位"
label="办理单位类型"
prop="handleDepartType"
:rules="{
required: true,
message: '请选择通知单位',
message: '请选择办理单位类型',
}"
>
<div>

28
src/views/sensitivePerception/ModelClue.vue

@ -104,7 +104,7 @@
<el-table-column
label="涉及人员"
prop="involvePoliceName"
width="100"
width="160"
>
<template #default="{ row }">
<div v-if="row.involvePoliceName">
@ -193,18 +193,18 @@
</el-row>
</div>
<el-dialog title="预警线索数据详情" v-model="show" width="80vw">
<el-dialog title="预警线索数据详情" v-model="show" width="50vw">
<div class="dialog-container">
<div class="row mt-10">
<div class="col col-6">
<div class="col col-12">
<label>预警时间</label>
<span>{{ activeModelClue.createTime }}</span>
</div>
<div class="col col-6">
<div class="col col-12">
<label>预警模型</label>
<span>{{ activeModelClue.modelName }}</span>
</div>
<div class="col col-6">
<div class="col col-12">
<label>涉及单位</label>
<span>
<span>{{
@ -221,15 +221,7 @@
<label>涉及人员</label>
<span>{{ activeModelClue.involvePoliceName }}</span>
</div>
</div>
<div class="row mt-10">
<div class="col col-24">
<label>预警内容</label>
<span>{{ activeModelClue.thingDesc }}</span>
</div>
</div>
<div class="row mt-10">
<div class="col col-6">
<div class="col col-12">
<label>分发状态</label>
<span>{{
getDictLable(
@ -239,9 +231,11 @@
}}</span>
</div>
</div>
<h3>详细信息</h3>
<div style="min-height: 200px">
<el-empty description="无数据" />
<div class="row mt-10" style="margin-bottom: 60px">
<div class="col col-24">
<label>预警内容</label>
<span>{{ activeModelClue.thingDesc }}</span>
</div>
</div>
</div>
</el-dialog>

29
src/views/sensitivePerception/ModelClueManual.vue

@ -1,10 +1,10 @@
<template>
<div class="container h100">
<el-row :gutter="20" class="h100">
<el-col :span="4">
<el-col :span="6">
<model-tree v-model="query.modelIds" />
</el-col>
<el-col :span="20">
<el-col :span="18">
<header>
<el-form :label-width="140">
<el-row>
@ -62,8 +62,8 @@
</div>
</div>
</header>
<div class="table-container">
<el-table :data="list" ref="tableRef">
<div class="table-container" v-loading="loading">
<el-table :data="list" ref="tableRef" max-height="600">
<el-table-column type="selection" width="55" />
<el-table-column
label="预警时间"
@ -168,7 +168,7 @@
<el-pagination
@size-change="getList"
@current-change="getList"
:page-sizes="[9, 18, 36]"
:page-sizes="[10, 20, 50, 100]"
v-model:page-size="query.size"
v-model:current-page="query.current"
layout="total, sizes, prev, pager, next"
@ -180,13 +180,13 @@
</el-row>
</div>
<el-dialog title="问题分发" v-model="manualShow" width="80vw" top="5vh">
<el-dialog title="问题分发" v-model="manualShow" width="80vw" top="5vh" style="margin-bottom: 0">
<header>
<el-form :label-width="140">
<el-row>
<el-col :span="8">
<el-form-item label="模型">
<el-select v-model="manualQuery.modelId">
<el-select v-model="manualQuery.modelId" clearable>
<el-option
v-for="item in modelOptions"
:key="item.value"
@ -201,6 +201,7 @@
<depart-tree-select
v-model="manualQuery.involveDepartId"
:check-strictly="false"
/>
</el-form-item>
</el-col>
@ -229,7 +230,8 @@
</header>
<div style="min-height: 500px">
<div class="table-container">
<el-table :data="filterManualList">
<el-table :data="filterManualList" max-height="580">
<el-table-column type="index" width="50" />
<el-table-column
label="预警时间"
prop="createTime"
@ -299,7 +301,7 @@
</footer>
</el-dialog>
<el-dialog title="任务分发" v-model="distributeShow" width="50vw" top="5vh">
<el-dialog title="任务分发" v-model="distributeShow" width="50vw" top="2vh" style="margin-bottom: 0">
<el-form :label-width="120" ref="formRef" :model="form" v-loading="submitLoading">
<el-form-item
label="任务名称"
@ -334,7 +336,9 @@
trigger: ['blur'],
}"
>
<el-select v-model="form.businessTypeCode" style="width: 280px">
<el-select v-model="form.businessTypeCode" style="width: 280px" @change="(val) => form.businessTypeCode = dict.businessType.filter(
(item) => item.dictValue === val
)[0].dictLabel">
<el-option
v-for="item in dict.businessType"
:key="item.id"
@ -561,10 +565,13 @@ watch(
}
);
const loading = ref(false)
function getList() {
loading.value = true
listModelClue(query.value).then((data) => {
list.value = data.records;
total.value = data.total;
loading.value = false
});
}
@ -640,6 +647,8 @@ function handleShowDistributeDialog() {
return;
}
distributeShow.value = true;
console.log(filterManualList.value)
form.value.taskName = filterManualList.value[0].modelName
}
const form = ref({

2
src/views/sensitivePerception/ModelClueTask.vue

@ -105,7 +105,7 @@
<el-pagination
@size-change="getList"
@current-change="getList"
:page-sizes="[9, 18, 36]"
:page-sizes="[10, 20, 50, 100]"
v-model:page-size="query.size"
v-model:current-page="query.current"
layout="total, sizes, prev, pager, next"

251
src/views/system/HandleResultMaping.vue

@ -0,0 +1,251 @@
<template>
<div class="container">
<header>
<el-row>
<el-col :span="12">
<div class="form-row flex">
<label class="text-center">局长信箱</label>
<div class="flex wrap query-box">
<el-input
placeholder="处理结果"
v-model="query.originId"
clearable
style="width: 280px"
/>
</div>
</div>
</el-col>
<el-col :span="12">
<div class="form-row flex">
<label class="text-center">数字督察</label>
<div class="flex wrap query-box">
<el-select
v-model="query.handleResultCode"
style="width: 280px"
clearable
>
<el-option
v-for="item in dict.handleResult"
:key="item.dictCode"
:value="item.dictValue"
:label="item.dictLabel"
/>
</el-select>
</div>
</div>
</el-col>
</el-row>
<div class="flex between mt-20 mb-26">
<el-button type="primary" @click="handleAdd">
<template #icon><icon name="el-icon-Plus" /></template>
新增</el-button
>
<div>
<el-button type="primary" @click="getList">
<template #icon
><icon name="el-icon-Search"
/></template>
查询</el-button
>
<el-button @click="reset">重置</el-button>
</div>
</div>
</header>
<div class="table-container">
<el-table :data="list">
<el-table-column label="局长信箱处理结果" prop="externalName" />
<el-table-column label="数字督察处理结果" prop="internalName" />
<el-table-column
label="最后修改时间"
prop="updateTime"
width="160"
/>
<el-table-column label="操作" width="160">
<template #default="{ row }">
<el-button type="primary" link @click="handleEdit(row)"
>编辑</el-button
>
<el-button type="danger" link @click="handleDel(row)"
>删除</el-button
>
</template>
</el-table-column>
</el-table>
</div>
<div class="flex end mt-8">
<el-pagination
@size-change="getList"
@current-change="getList"
:page-sizes="[10, 20, 50]"
v-model:page-size="query.size"
v-model:current-page="query.current"
layout="total, sizes, prev, pager, next"
:total="total"
>
</el-pagination>
</div>
</div>
<el-dialog
v-model="show"
:title="mode === 'add' ? '新增处理结果映射' : '编辑处理结果映射'"
width="600"
>
<el-form :label-width="140" :model="formData" ref="fomrRef">
<el-form-item
label="局长信箱处理结果"
prop="externalName"
:rules="{
required: true,
message: '请输入',
trigger: ['blur'],
}"
>
<el-input
v-model="formData.externalName"
clearable
style="width: 280px"
placeholder="请输入"
/>
</el-form-item>
<el-form-item
label="数字督察处理结果"
prop="internalId"
:rules="{
required: true,
message: '请输入',
trigger: ['blur'],
}"
>
<el-select
v-model="formData.internalId"
@change="(val) => {
formData.internalName = dict.handleResult
.find((obj) => val === obj.dictValue).dictLabel
}"
style="width: 280px"
clearable
>
<el-option
v-for="item in dict.handleResult"
:key="item.dictCode"
:value="item.dictValue"
:label="item.dictLabel"
/>
</el-select>
</el-form-item>
</el-form>
<footer class="flex end mt-40">
<el-button @click="show = false" size="large">取消</el-button>
<el-button type="primary" @click="submit" size="large"
>确定</el-button
>
</footer>
</el-dialog>
</template>
<script setup>
import {
listHandleResultMaping,
addHandleResultMaping,
updateHandleResultMaping,
delHandleResultMaping,
} from "@/api/system/handleResultMaping";
import feedback from "@/utils/feedback";
import useCatchStore from "@/stores/modules/catch";
const catchSotre = useCatchStore();
const dict = catchSotre.getDicts(["handleResult"]);
function getProblemType(id) {
console.log(dictContent);
dictContent.forEach(() => {
return "111";
});
for (let i = 0; i < dictContent.length; i++) {
const obj1 = dictContent[i];
if (obj1.id === id) {
return obj1.name;
}
if (!obj1.children) {
continue;
}
for (let j = 0; j < obj1.children.length; j++) {
const obj2 = obj1.children[j];
if (obj2.id === id) {
return obj1.name + " / " + obj2.name;
}
if (!obj2.children) {
continue;
}
for (let k = 0; k < obj2.children.length; k++) {
const obj3 = obj2.children[k];
if (obj3.id === id) {
return obj1.name + " / " + obj2.name + " / " + obj3.name;
}
}
}
}
}
const query = ref({
current: 1,
size: 10,
});
const list = ref([]);
const total = ref(0);
function getList() {
listHandleResultMaping(query.value).then((data) => {
list.value = data.records;
total.value = data.total;
});
}
function reset() {
query.value = {
current: 1,
size: 10,
};
getList();
}
onMounted(() => {
getList();
});
const show = ref(false);
const mode = ref("add");
const formData = ref({});
const fomrRef = ref();
function handleAdd() {
formData.value = { internalId: "" };
show.value = true;
mode.value = "add";
}
function handleEdit(row) {
formData.value = { ...row };
show.value = true;
mode.value = "edit";
}
async function handleDel(row) {
await feedback.confirm("确定要删除该数据?");
await delHandleResultMaping(row.id);
getList();
feedback.msgSuccess("删除成功");
}
async function submit() {
await fomrRef.value.validate();
if (mode.value === "add") {
await addHandleResultMaping(formData.value);
} else {
await updateHandleResultMaping(formData.value);
}
show.value = false;
formData.value = {};
getList();
feedback.msgSuccess("操作成功");
}
</script>
<style lang="scss" scoped>
</style>

46
src/views/system/Menu.vue

@ -52,10 +52,7 @@
<el-button type="primary" link @click="handleEdit(row)"
>编辑</el-button
>
<el-button
type="danger"
link
@click="handleDelete(row)"
<el-button type="danger" link @click="handleDelete(row)"
>删除</el-button
>
</template>
@ -128,7 +125,7 @@
v-if="formData.menuType === MenuEnum.CATALOGUE"
:rules="{
required: true,
message: '请选择图标'
message: '请选择图标',
}"
prop="icon"
>
@ -262,7 +259,9 @@
</el-form>
<footer class="flex end">
<el-button @click="show = false">取消</el-button>
<el-button type="primary" @click="submit">确定</el-button>
<el-button type="primary" @click="submit" :disabled="disabled"
>确定</el-button
>
</footer>
</el-dialog>
</template>
@ -310,7 +309,7 @@ const querySearch = (queryString, cb) => {
const mode = ref<string>("add");
watch(mode, (val) => {
if (val === "add") {
initFormData()
initFormData();
}
});
@ -323,27 +322,30 @@ function initFormData() {
}
function handleAdd() {
show.value = true
mode.value = 'add'
show.value = true;
mode.value = "add";
}
function submit() {
formRef.value.validate((flag) => {
if (flag) {
const disabled = ref(false);
async function submit() {
await formRef.value.validate();
disabled.value = true;
try {
if (mode.value === "add") {
addMenu(formData.value).then(() => {
show.value = false;
initFormData()
getList();
});
await addMenu(formData.value);
initFormData();
} else {
updateMenu(formData.value).then(() => {
show.value = false;
getList();
});
await updateMenu(formData.value);
}
} catch(e) {
console.error(e)
disabled.value = false;
return
}
});
disabled.value = false;
show.value = false;
getList();
feedback.msgSuccess('操作成功')
}
function handleEdit(row) {

105
src/views/system/Police.vue

@ -256,13 +256,9 @@
</div>
</template>
</el-table-column>
<!-- <el-table-column label="是否有账号" width="100" align="center">
<template #default="{ row }">
<span></span>
</template>
</el-table-column> -->
<el-table-column label="操作" width="220">
<template #default="{ row }">
<div class="flex gap">
<el-button
type="primary"
link
@ -270,14 +266,31 @@
v-perms="['police:add']"
>编辑</el-button
>
<div v-perms="['police:auth']">
<el-tooltip
effect="dark"
content="该警员身份证为空或无用户数据"
placement="top"
v-if="!row.idCode || !row.userId"
>
<div>
<el-button
type="primary"
link
:disabled="true"
>权限设置</el-button
>
</div>
</el-tooltip>
<el-button
type="primary"
link
@click="handleEditAuth(row)"
v-perms="['police:auth']"
v-if="row.idCode"
v-else
>权限设置</el-button
>
</div>
<el-button
type="danger"
link
@ -285,6 +298,7 @@
v-perms="['police:del']"
>删除</el-button
>
</div>
</template>
</el-table-column>
</el-table>
@ -303,6 +317,12 @@
</div>
</el-tab-pane>
<el-tab-pane label="异常警员">
<template #label>
<el-badge :value="abnormalTotal" v-if="abnormalTotal > 0">
<span class="tab-nav-title">异常警员</span>
</el-badge>
<span class="tab-nav-title" v-else>异常警员</span>
</template>
<header>
<el-form :label-width="114">
<el-row>
@ -381,7 +401,6 @@
</header>
<div class="table-container" v-loading="loading">
<el-table :data="abnormalPolices" row-key="id">
<el-table-column label="姓名" prop="name" width="90" />
<el-table-column
label="警号"
@ -439,7 +458,11 @@
prop="idCode"
width="200"
/>
<el-table-column label="异常原因" prop="delReason" show-overflow-tooltip />
<el-table-column
label="异常原因"
prop="delReason"
show-overflow-tooltip
/>
</el-table>
</div>
<div class="flex end mt-8">
@ -465,6 +488,21 @@
:lock-scroll="false"
>
<el-form :label-width="160">
<el-form-item label="用户角色">
<el-select
v-model="authForm.roleIds"
placeholder="请选择角色"
multiple
clearable
>
<el-option
v-for="item in roles"
:key="item.roleId"
:value="item.roleId"
:label="item.roleName"
/>
</el-select>
</el-form-item>
<el-form-item label="机构权限">
<depart-tree-select
v-model="authForm.departs"
@ -640,6 +678,33 @@
>
</div>
</el-form-item>
<el-form-item label="是否创建新用户" v-if="mode === 'add'">
<el-switch
v-model="form.createUserFlag"
inline-prompt
active-text="是"
inactive-text="否"
:active-value="true"
:inactive-value="false"
/>
</el-form-item>
<el-form-item
label="用戶密码"
v-if="mode === 'add' && form.createUserFlag"
:rules="{
required: true,
message: '请输入用户密码',
trigger: ['blur'],
}"
prop="password"
>
<el-input
type="password"
v-model="form.password"
placeholder="请输入用戶密码"
/>
<p class="text-small">用户密码默认为123456</p>
</el-form-item>
<!-- <el-form-item label="婚姻状况">
<el-radio-group v-model="form.maritalStatus">
@ -696,7 +761,7 @@
prop="delReason"
:rules="{
required: true,
message: '请输入姓名',
message: '请输入其他原因',
}"
v-if="delFormData.option === `其他`"
>
@ -710,7 +775,7 @@
</el-form-item>
</el-form>
<footer class="flex end">
<el-button @click="show = false">取消</el-button>
<el-button @click="delDialog = false">取消</el-button>
<el-button type="primary" @click="handleDel">确定</el-button>
</footer>
</el-dialog>
@ -784,8 +849,8 @@ const abnormalPolices = ref([]);
const abnormalQuery = ref({
current: 1,
size: 10,
})
const abnormalTotal = ref(0)
});
const abnormalTotal = ref(0);
function getAbnormalList() {
loading.value = true;
listAbnormalPolice(abnormalQuery.value).then((data) => {
@ -803,7 +868,6 @@ function abnormalReset() {
getList();
}
const authShow = ref(false);
const authForm = ref({});
let activeIdCode = "";
@ -818,12 +882,15 @@ function handleEditAuth(row) {
function authSubmit() {
updatePoliceAuths(activeIdCode, authForm.value).then(() => {
authShow.value = false;
feedback.msgSuccess("操作成功");
feedback.msgSuccess("权限设置成功");
getList();
});
}
const mode = ref("add");
const form = ref({});
const form = ref({
password: "123456",
});
const fomrRef = ref(null);
const show = ref(false);
@ -845,7 +912,9 @@ async function submit() {
await fomrRef.value.validate();
if (mode.value === "add") {
await addPolice(form.value);
form.value = {};
form.value = {
password: "123456",
};
} else {
await updatePolice(form.value);
}
@ -925,7 +994,7 @@ async function handleDel(row) {
delDialog.value = false;
delFormData.value = {};
getList();
getAbnormalList()
getAbnormalList();
}
function handleUploadImgSuccess(result, file) {

295
src/views/system/VideoConfig.vue

@ -0,0 +1,295 @@
<template>
<div class="container">
<header class="mb-20">
<el-form :label-width="114">
<el-row>
<el-col :span="6">
<el-form-item label="单位">
<el-tree-select
v-model="query.departId"
:data="departs"
:props="{ label: 'shortName', value: 'id' }"
node-key="id"
:default-expanded-keys="['12630']"
clearable
filterable
check-strictly
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div class="flex between">
<el-button type="primary" @click="handleShowAdd">
<template #icon>
<icon name="el-icon-Plus" />
</template>
新增视频配置</el-button
>
<div>
<el-button type="primary" @click="getList">
<template #icon>
<icon name="el-icon-Search" />
</template>
查询</el-button
>
<el-button @click="reset">重置</el-button>
</div>
</div>
</header>
<div class="table-container">
<el-table :data="list">
<el-table-column
label="单位"
prop="departName"
show-overflow-tooltip
/>
<el-table-column label="设备" prop="deviceName" />
<el-table-column
label="视频地址"
prop="videoUrl"
show-overflow-tooltip
/>
<el-table-column
label="排序"
prop="sortId"
width="90"
align="center"
/>
<el-table-column
label="创建时间"
prop="createTime"
width="180"
/>
<el-table-column label="操作" width="200">
<template #default="{ row }">
<el-button
type="primary"
link
@click="handleEdit(row)"
v-perms="['user:edit']"
>编辑</el-button
>
<el-button type="danger" link @click="handleDel(row)"
>删除</el-button
>
</template>
</el-table-column>
</el-table>
</div>
<div class="flex end mt-8">
<el-pagination
@size-change="getList"
@current-change="getList"
:page-sizes="[10, 20, 50]"
v-model:page-size="query.size"
v-model:current-page="query.current"
layout="total, sizes, prev, pager, next"
:total="total"
>
</el-pagination>
</div>
</div>
<el-dialog
:title="mode === 'add' ? '新增视频配置' : '编辑视频配置'"
v-model="show"
width="600"
>
<el-form :label-width="120" ref="formRef" :model="form">
<el-form-item
label="单位"
:rules="{
required: true,
message: '请选择',
trigger: ['blur'],
}"
prop="departId"
>
<el-tree-select
v-model="form.departId"
:data="departs"
:props="{ label: 'shortName', value: 'id' }"
node-key="id"
:default-expanded-keys="['12630']"
clearable
filterable
check-strictly
@node-click="handleDepartChange"
/>
</el-form-item>
<el-form-item
label="设备"
:rules="{
required: true,
message: '请选择',
trigger: ['blur'],
}"
prop="deviceId"
>
<el-tree-select
:data="devices"
v-model="form.deviceId"
:props="{
label: 'name',
value: 'deviceId',
disabled: nodeDisabled,
}"
node-key="id"
clearable
filterable
@current-change="handleDeviceChange"
>
<template #default="{ node, data }">
<div>
<span class="mr-10">{{ data.name }}</span>
<el-tag type="success" size="small" v-if="data.status === 'ON'">在线</el-tag>
<el-tag type="danger" size="small" v-if="data.status === 'OFF'">离线</el-tag>
</div>
</template>
</el-tree-select>
</el-form-item>
<el-form-item label="排序" prop="sortId">
<el-input
v-model="form.sortId"
type="number"
placeholder="排序"
/>
</el-form-item>
<el-form-item label="视频">
<div>
<div style="width: 400px">
<VideoPlay :url="form.videoUrl" />
</div>
<p style="height: 32px">{{ form.videoUrl }}</p>
</div>
</el-form-item>
</el-form>
<footer class="flex end">
<el-button @click="show = false" size="large">取消</el-button>
<el-button type="primary" @click="submit" size="large"
>确定</el-button
>
</footer>
</el-dialog>
</template>
<script setup>
import {
listVideoConfig,
listDevice,
addVideoConfig,
updateVideoConfig,
delVideoConfig,
getVideoWsUrl,
} from "@/api/system/videoConfig";
import { getCountyAndCityBureausTree } from "@/api/system/depart";
import feedback from "@/utils/feedback";
const list = ref([]);
const query = ref({
current: 1,
size: 10,
});
const total = ref(0);
function getList() {
listVideoConfig(query.value).then((data) => {
list.value = data.records;
total.value = data.total;
});
}
function reset() {
query.value = {
current: 1,
size: 10,
};
getList();
}
const devices = ref([]);
const departs = ref([]);
let videoWsUrl = "";
onMounted(() => {
getList();
listDevice().then((data) => {
devices.value = data;
});
getCountyAndCityBureausTree().then((data) => {
departs.value = data;
});
getVideoWsUrl().then((data) => {
videoWsUrl = data;
});
});
const show = ref(false);
const mode = ref("add");
const form = ref({});
const formRef = ref(null);
function handleEdit(row) {
show.value = true;
mode.value = "edit";
form.value = row;
}
function handleDepartChange(node) {
form.value.departName = node.shortName;
}
function handleDeviceChange(node) {
if (departs.value.length > 0) {
form.value.parentId = devices.value[0].deviceId
}
form.value.deviceName = node.name;
}
watch(() => form.value.deviceId, () => {
form.value.videoUrl = `${videoWsUrl}rtp/${form.value.parentId}_${form.value.deviceId}.live.flv`;
})
function submit() {
formRef.value.validate((flag) => {
if (flag) {
if (mode.value === "edit") {
updateVideoConfig(form.value).then((data) => {
show.value = false;
form.value = {};
getList();
feedback.msgSuccess("操作成功");
});
} else {
addVideoConfig(form.value).then((data) => {
show.value = false;
form.value = {};
getList();
feedback.msgSuccess("操作成功");
});
}
}
});
}
watch(mode, (val) => {
if (val === "add") {
form.value = {};
}
});
function handleShowAdd() {
mode.value = "add";
show.value = true;
}
async function handleDel(row) {
await feedback.confirm("确定要删除该数据?");
await delVideoConfig(row.id);
getList();
}
function nodeDisabled(data) {
return data.status === "OFF";
}
</script>
<style lang="scss" scoped>
</style>

1
src/views/system/Wqzg.vue

@ -54,6 +54,7 @@
</el-table-column>
<el-table-column label="警员姓名" prop="empName" width="200" />
<el-table-column label="警号" prop="empNo" width="200" />
<el-table-column label="身份证" prop="idCode" width="200" />
<el-table-column
label="市局维权专干"
align="center"

29
src/views/work/Alarm.vue

@ -97,7 +97,11 @@
width="100"
show-overflow-tooltip
/>
<el-table-column label="提醒内容" prop="alarmContent" show-overflow-tooltip />
<el-table-column
label="提醒内容"
prop="alarmContent"
show-overflow-tooltip
/>
<el-table-column label="回复情况" width="110">
<template #default="{ row }">
<el-text v-if="row.replyState == 1" class="mx-1"
@ -134,7 +138,6 @@
</div>
</main>
<el-dialog title="查看详情" v-model="dialogShow" width="800">
<el-form :model="showData" :label-width="120" ref="fomrRef">
<el-row>
@ -179,11 +182,11 @@
</el-row>
<el-row
style="margin-top: 10px"
v-if="showData.files != undefined && showData.files.length > 0"
v-if="
showData.files != undefined && showData.files.length > 0
"
>
<el-form-item label="问题附件">
</el-form-item>
<el-form-item label="问题附件"> </el-form-item>
</el-row>
</el-form>
<footer class="flex end">
@ -191,16 +194,12 @@
</footer>
</el-dialog>
</div>
</template>
<script setup>
import moment from "moment";
import { Clock } from "@element-plus/icons-vue";
import {
alarmNotificationPages,
alarmFiles,
} from "@/api/work/alarm";
import { alarmNotificationPages, alarmFiles } from "@/api/work/alarm";
import feedback from "@/utils/feedback";
import useCatchStore from "@/stores/modules/catch";
@ -322,7 +321,6 @@ function handleAction(row) {
}
const router = useRouter();
</script>
<style lang="scss" scoped>
.form-row {
@ -351,6 +349,11 @@ const router = useRouter();
}
.query-box {
gap: 10px 20px;
> * {
margin-right: 20px;
&:last-child {
margin-right: 0;
}
}
}
</style>

26
src/views/work/BatchDistribute.vue

@ -83,7 +83,8 @@
</el-table-column>
</el-table>
</div>
<div class="flex end mt-8">
<div class="flex between v-center mt-8">
<div>说明批量下发列表展示问题导入标准模板及其他来源问题导入模板下发的任务情况</div>
<el-pagination
@size-change="getList"
@current-change="getList"
@ -146,6 +147,7 @@
>问题批量导入标准模板.xlsx 下载</a
>
</div>
<div class="mt-10">说明请上传问题批量导入标准模板上传成功后点击下一步进行数据校验</div>
</template>
<template v-if="activeStep === 1">
<div class="table-container">
@ -383,7 +385,7 @@
</el-dialog>
</template>
<script setup>
import { listNegativeTaskImport, importNegative, distributeNegative, listGroupByDepart } from "@/api/work/negativeTask";
import { listNegativeTask, importNegative, distributeNegative, listGroupByDepart } from "@/api/work/negativeTask";
import feedback from "@/utils/feedback";
import useCatchStore from "@/stores/modules/catch";
import { BASE_PATH } from "@/api/request";
@ -392,22 +394,34 @@ const catchStore = useCatchStore();
const dict = catchStore.getDicts([
"approvalFlow",
"distributionFlow",
"businessType",
"businessType"
]);
const router = useRouter()
const query = ref({});
const query = ref({
size: 10,
current: 1,
category: '0'
});
const list = ref([]);
const total = ref(0);
function getList() {
listNegativeTaskImport(query.value).then((data) => {
listNegativeTask(query.value).then((data) => {
list.value = data.records;
total.value = data.total;
});
}
function reset() {
query.value = {
size: 10,
current: 1,
category: '0'
};
getList();
}
onMounted(() => {
getList();
});

3
src/views/work/Done.vue

@ -370,7 +370,8 @@
</el-table-column>
</el-table>
</div>
<div class="flex end mt-8">
<div class="flex between v-center mt-8">
<div>说明已办列表展示当前与本人处理过但尚未办结的工作</div>
<el-pagination
@size-change="getList"
@current-change="getList"

528
src/views/work/MyCountersign.vue

@ -0,0 +1,528 @@
<template>
<div class="container">
<header>
<el-form :label-width="120">
<el-row>
<el-col :span="6">
<el-form-item label="问题发现时间">
<date-time-range-picker-ext
v-model="query.discoveryTime"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="问题发生时间">
<date-time-range-picker-ext
v-model="query.happenTime"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="问题录入时间">
<date-time-range-picker-ext
v-model="query.crtTime"
/>
</el-form-item>
</el-col>
</el-row>
<div class="form-row flex">
<label class="text-center">问题信息</label>
<div class="flex wrap query-box">
<el-input
placeholder="问题编号 / 样本源头编号"
v-model="query.originId"
clearable
style="width: 200px"
/>
<el-input
placeholder="涉及案件 / 警情编号"
v-model="query.caseNumber"
clearable
style="width: 200px"
/>
<el-input
placeholder="事情简要描述"
v-model="query.thingDesc"
clearable
style="width: 260px"
/>
<el-select
style="width: 146px"
placeholder="业务类别"
clearable
v-model="query.businessTypeCode"
>
<el-option
v-for="item in dict.businessType"
:key="item.id"
:label="item.dictLabel"
:value="item.dictValue"
/>
</el-select>
<el-tree-select
:data="dictProblemSources"
:props="{ value: 'id' }"
node-key="id"
v-model="query.problemSourcesCode"
clearable
filterable
multiple
collapse-tags
style="width: 200px"
placeholder="问题来源"
/>
<el-select
style="width: 146px"
placeholder="专项督察"
clearable
v-model="query.specialSupervision"
>
<el-option
v-for="item in dict.specialSupervision"
:key="item.id"
:label="item.dictLabel"
:value="item.dictValue"
/>
</el-select>
<el-input
placeholder="通报期数"
style="width: 146px"
v-model="query.reportNumber"
clearable
/>
</div>
</div>
<div class="form-row flex">
<label class="text-center">核查情况</label>
<div class="flex wrap query-box">
<div style="width: 200px">
<depart-tree-select
v-model="query.involveDepartId"
placeholder="涉及单位"
/>
</div>
<div style="width: 200px">
<depart-tree-select
v-model="query.handleDepartId"
placeholder="办理单位"
/>
</div>
<el-select
style="width: 120px"
placeholder="是否属实"
clearable
v-model="query.checkStatus"
>
<el-option
v-for="item in dict.inspectCase"
:key="item.id"
:label="item.dictLabel"
:value="item.dictValue"
/>
</el-select>
<el-select
style="width: 120px"
placeholder="是否整改"
clearable
v-model="query.isRectifyCode"
>
<el-option
v-for="item in dict.isRectify"
:key="item.id"
:label="item.dictLabel"
:value="item.dictValue"
/>
</el-select>
<div class="flex gap-4">
<el-select
v-model="query.blameKey"
style="width: 90px"
@change="delete query.blameValue"
>
<el-option value="name" label="姓名" />
<el-option value="empNo" label="警号" />
<el-option value="idCode" label="身份证" />
</el-select>
<el-input
placeholder="涉及人员"
v-model="query.blameValue"
clearable
style="width: 190px"
/>
</div>
</div>
</div>
<div class="form-row flex">
<label class="text-center">其他选项</label>
<div class="flex wrap query-box">
<el-select
style="width: 200px"
placeholder="流程阶段"
clearable
v-model="query.flowKey"
>
<el-option
v-for="item in flowNodes"
:key="item.flowKey"
:label="item.flowName"
:value="item.flowKey"
/>
</el-select>
<el-select
style="width: 120px"
placeholder="办理状态"
clearable
v-model="query.processingStatus"
multiple
>
<el-option
v-for="item in dict.processingStatus"
:key="item.id"
:label="item.dictLabel"
:value="item.dictValue"
/>
</el-select>
<div class="flex gap-4" style="height: 32px">
<el-select
v-model="query.responderKey"
style="width: 90px"
@change="delete query.responderValue"
>
<el-option value="name" label="姓名" />
<el-option value="phone" label="电话" />
</el-select>
<el-input
placeholder="投诉反映人"
v-model="query.responderValue"
clearable
style="width: 190px"
/>
</div>
<el-select
style="width: 120px"
placeholder="申请延期"
clearable
v-model="query.extensionFlag"
>
<el-option label="已申请" :value="true" />
<el-option label="未申请" :value="false" />
</el-select>
<el-select
style="width: 146px"
placeholder="下发单位的层级"
clearable
v-model="query.crtDepartLevel"
>
<el-option label="市局下发" :value="0" />
<el-option label="二级机构下发" :value="2" />
</el-select>
</div>
</div>
</el-form>
<div class="flex between mt-20 mb-26">
<el-button type="primary" @click="handleExport"
>数据导出</el-button
>
<div>
<el-button type="primary" @click="getList">
<template #icon
><icon name="el-icon-Search"
/></template>
查询</el-button
>
<el-button @click="reset">重置</el-button>
</div>
</div>
</header>
<main>
<div class="table-container" v-loading="loading">
<el-table
:data="list"
@sort-change="handleTableSort"
ref="tableRef"
>
<el-table-column type="expand">
<template #default="{ row }">
<div class="row mt-10">
<div class="col col-6">
<label>样本源头编号</label>
<span>{{ row.originId }}</span>
</div>
<div class="col col-6">
<label>问题发现时间</label>
<span>{{ row.discoveryTime }}</span>
</div>
<div class="col col-6">
<label>问题发生时间</label>
<span>{{ row.happenTime || "/" }}</span>
</div>
</div>
<div class="row mt-10">
<div class="col col-6">
<label>问题来源</label>
<span>{{ row.problemSources }}</span>
</div>
<div class="col col-6">
<label>业务类别</label>
<span>{{ row.businessTypeName }}</span>
</div>
<div class="col col-12">
<label>涉嫌问题</label>
<span>{{
getInvolveProblem(
row.involveProblem,
dict.suspectProblem
) || "/"
}}</span>
</div>
</div>
<div class="row mt-10">
<div class="col col-6" v-if="row.responderName">
<label>投诉反映人</label>
<span>{{ row.responderName }}</span>
</div>
<div class="col col-6" v-if="row.contactPhone">
<label>联系电话</label>
<span>{{ row.contactPhone }}</span>
</div>
</div>
<div class="row mt-10">
<div class="col col-6">
<label>涉及警种</label>
<span>{{ row.policeTypeName }}</span>
</div>
<div class="col col-6">
<label>涉及单位</label>
<span>{{
row.involveDepartName || "/"
}}</span>
</div>
</div>
<div class="row mt-10">
<div class="col col-24">
<label>事情简要描述</label>
<span>{{ row.thingDesc }}</span>
</div>
</div>
</template>
</el-table-column>
<el-table-column
label="问题录入时间"
prop="crtTime"
width="150"
sortable="custom"
/>
<el-table-column
label="问题发现时间"
prop="discoveryTime"
width="150"
sortable="custom"
/>
<el-table-column
label="问题来源"
prop="problemSources"
width="110"
/>
<el-table-column
label="业务类别"
prop="businessTypeName"
width="110"
/>
<el-table-column
label="问题内容"
prop="thingDesc"
show-overflow-tooltip
/>
<el-table-column label="办理单位" show-overflow-tooltip>
<template #default="{ row }">
<span
>{{ row.handleSecondDepartName
}}{{ row.handleThreeDepartName }}</span
>
</template>
</el-table-column>
<el-table-column
label="是否属实"
prop="checkStatusName"
width="100"
align="center"
/>
<el-table-column label="办理状态" width="110">
<template #default="{ row }">
<el-tag
:type="
row.processingStatus ===
ProcessingStatus.COMPLETED
? 'success'
: 'primary'
"
v-if="row.processingStatus"
>{{
getDictLable(
dict.processingStatus,
row.processingStatus
)
}}</el-tag
>
</template>
</el-table-column>
<el-table-column
label="当前处理对象"
prop="currentProcessingObject"
show-overflow-tooltip
>
<template #default="{ row }">
<span
v-if="
row.processingStatus ===
ProcessingStatus.COMPLETED
"
></span
>
<span v-else>{{
row.currentProcessingObject
}}</span>
</template>
</el-table-column>
<el-table-column label="操作" width="120">
<template #default="{ row }">
<el-button
type="primary"
link
@click="handleAction(row)"
>详情</el-button
>
</template>
</el-table-column>
</el-table>
</div>
<div class="flex between v-center mt-8">
<div>说明会签列表展示拥有同样权限的专班成员会签过的工作</div>
<el-pagination
@size-change="getList"
@current-change="getList"
:page-sizes="[10, 20, 50, 100]"
v-model:page-size="query.size"
v-model:current-page="query.current"
layout="total, sizes, prev, pager, next"
:total="total"
>
</el-pagination>
</div>
</main>
</div>
<negative-dialog
v-model="show"
:id="activeNegativeId"
@close="show = false"
ref="negativeDialogRef"
/>
</template>
<script setup>
import moment from "moment";
import { ElLoading } from "element-plus";
import {
listMyCountersign,
negativeExport
} from "@/api/work/myCountersign";
import { getDictLable, getInvolveProblem } from "@/utils/util";
import feedback from "@/utils/feedback";
import { ProcessingStatus } from "@/enums/flowEnums";
import useCatchStore from "@/stores/modules/catch";
const catchStore = useCatchStore();
const dict = catchStore.getDicts([
"businessType",
"inspectCase",
"isRectify",
"processingStatus",
"suspectProblem",
"policeType",
"specialSupervision",
]);
const flowNodes = catchStore.getFlowNodes();
const dictProblemSources = catchStore.getDictProblemSources();
const queryCrumbs = ref([]);
const query = ref({
current: 1,
size: 10,
responderKey: "name",
blameKey: "name"
});
const list = ref([]);
const total = ref(0);
const loading = ref(true);
function getList() {
loading.value = true;
listMyCountersign(query.value).then((data) => {
list.value = data.records;
total.value = data.total;
loading.value = false;
});
}
function handleTableSort(orderObj) {
if (orderObj.order) {
query.value.order = orderObj.order;
query.value.orderProp = orderObj.prop;
} else {
query.value.order = "";
query.value.orderProp = "";
}
getList();
}
const tableRef = ref();
function reset() {
query.value = {
current: 1,
size: 10,
responderKey: "name",
blameKey: "name"
};
tableRef.value.clearSort();
getList();
}
onMounted(() => {
getList();
});
const show = ref(false);
const activeNegativeId = ref("");
function handleAction(row) {
show.value = true;
activeNegativeId.value = row.id;
}
const router = useRouter();
async function handleExport() {
await feedback.confirm("请确定导出当前页面所有数据");
const loading = ElLoading.service({
lock: true,
text: "导出中...",
background: "rgba(0, 0, 0, 0.5)",
});
await negativeExport(query.value);
loading.close();
await feedback.confirm("导出任务已生成,请到“导出记录”页面查看");
router.push("/negative/export");
}
</script>
<style lang="scss" scoped>
</style>

14
src/views/work/NegativeImport.vue

@ -1,11 +1,12 @@
<template>
<div class="container">
<header>
<div class="flex gap">
<el-upload
:multiple="false"
:show-file-list="false"
:action="`${BASE_PATH}/negative/import`"
:action="`${BASE_PATH}/negative/import/sj`"
:headers="{ Authorization: getToken() }"
:before-upload="beforeUpload"
@success="handleSuccess"
@ -16,18 +17,9 @@
<el-button type="primary">
<template #icon>
<icon name="el-icon-Upload" />
</template>
黄赌毒历史问题下发</el-button
</template>审计问题</el-button
>
</el-upload>
<a
class="link"
:href="`${BASE_PATH}/templates/黄赌问题问题下发模板.xls`"
target="__blank"
style="padding: 8px"
v-perms="['police:import']"
>黄赌毒历史问题模板下载</a
>
</div>
</header>
</div>

6
src/views/work/NegativeTask.vue

@ -56,6 +56,7 @@
type="primary"
link
@click="handleDownload(row)"
:disabled="row.status !== '0'"
>下载</el-button
>
</template>
@ -84,6 +85,7 @@ const list = ref([]);
const query = ref({
size: 10,
current: 1,
category: '2'
});
const total = ref(0);
@ -98,6 +100,7 @@ function reset() {
query.value = {
size: 10,
current: 1,
category: '2'
};
getList();
}
@ -107,6 +110,9 @@ onMounted(() => {
});
function handleDownload(row) {
if (row.status !== '1') {
}
fetch(`${BASE_PATH}/file/stream${row.filePath}`)
.then((response) => {
console.log(response);

141
src/views/work/News.vue

@ -75,6 +75,9 @@
<el-table-column label="动态内容" prop="contentTxt" />
<el-table-column label="操作" width="160">
<template #default="{ row }">
<el-button type="primary" link @click="handleShow(row)"
>查看</el-button
>
<el-button type="primary" link @click="handleEdit(row)"
>编辑</el-button
>
@ -110,8 +113,6 @@
ref="fomrRef"
style="min-height: 40vh"
>
<el-row>
<el-col :span="12">
<el-form-item
label="动态类型"
prop="source"
@ -127,35 +128,10 @@
:key="item.dictCode"
:value="item.dictValue"
>{{ item.dictLabel
}}{{
item.remark ? `(${item.remark})` : ""
}}</el-radio
}}{{ item.remark ? `(${item.remark})` : "" }}</el-radio
>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
label="发布时间"
prop="releaseTime"
:rules="{
required: true,
message: '请选择',
trigger: ['blur'],
}"
>
<el-date-picker
v-model="formData.releaseTime"
type="datetime"
placeholder="请选择"
value-format="YYYY-MM-DD HH:mm"
time-format="HH:mm"
style="width: 100%"
/>
</el-form-item>
</el-col>
</el-row>
<el-form-item
label="动态分类"
@ -167,13 +143,28 @@
}"
>
<el-radio-group v-model="formData.workType">
<template v-if="formData.source !== '审计工作动态'">
<el-radio
v-for="item in dict.newsWorkType"
:key="item.dictCode"
:value="item.dictValue"
>{{ item.dictLabel
}}{{ item.remark ? `(${item.remark})` : "" }}</el-radio
}}{{
item.remark ? `(${item.remark})` : ""
}}</el-radio
>
</template>
<template v-else>
<el-radio
v-for="item in dict.newsSjWorkType"
:key="item.dictCode"
:value="item.dictValue"
>{{ item.dictLabel
}}{{
item.remark ? `(${item.remark})` : ""
}}</el-radio
>
</template>
</el-radio-group>
</el-form-item>
<el-form-item
@ -186,9 +177,32 @@
}"
>
<div style="width: 300px">
<depart-tree-select v-model="formData.departId" @node-click="(node) => formData.departName = node.shortName" />
<depart-tree-select
v-model="formData.departId"
@node-click="
(node) => (formData.departName = node.shortName)
"
/>
</div>
</el-form-item>
<el-form-item
label="发布时间"
prop="releaseTime"
:rules="{
required: true,
message: '请选择',
trigger: ['blur'],
}"
>
<el-date-picker
v-model="formData.releaseTime"
type="datetime"
placeholder="请选择"
value-format="YYYY-MM-DD HH:mm"
time-format="HH:mm"
style="width: 300px"
/>
</el-form-item>
<el-form-item
label="动态内容"
prop="contentTxt"
@ -206,6 +220,9 @@
:autosize="{ minRows: 6, maxRows: 10 }"
/>
</el-form-item>
<el-form-item label="附件">
<file-upload v-model:files="formData.files" accept="image/*" />
</el-form-item>
</el-form>
<footer class="flex end mt-40">
<el-button @click="show = false" size="large">取消</el-button>
@ -214,14 +231,54 @@
>
</footer>
</el-dialog>
<el-dialog v-model="detailShow" title="工作动态详情" width="60vw">
<div style="padding: 20px 40px; min-height: 50vh">
<div class="row">
<div class="col col-12">
<label>动态类型</label>
<span>{{ activeRow.source }}</span>
</div>
<div class="col col-12">
<label>动态分类</label>
<span>{{ activeRow.workType }}</span>
</div>
<div class="col col-12">
<label>发布单位</label>
<span>{{ activeRow.departName }}</span>
</div>
<div class="col col-12">
<label>发布时间</label>
<span>{{ activeRow.releaseTime }}</span>
</div>
</div>
<div>
<div class="text-primary mt-10">内容</div>
<div class="content mb-20">{{ activeRow.contentTxt }}</div>
</div>
<div>
<div class="text-primary mt-10 mb-10">附件</div>
<file-list
:files="activeRow.files"
v-if="activeRow.files.length > 0"
/>
<el-empty v-else description="无附件" style="--el-empty-image-width: 50px" />
</div>
</div>
</el-dialog>
</template>
<script setup>
import moment from "moment";
import { listNews, addNews, updateNews, delNews } from "@/api/work/news";
import feedback from "@/utils/feedback";
import useCatchStore from "@/stores/modules/catch";
const catchStore = useCatchStore();
const dict = catchStore.getDicts(["newsWorkType", "newsWorkSource"]);
const dict = catchStore.getDicts([
"newsWorkType",
"newsSjWorkType",
"newsWorkSource",
]);
const query = ref({
current: 1,
@ -255,12 +312,20 @@ const formData = ref({});
const fomrRef = ref();
function handleAdd() {
formData.value = { internalId: "" };
formData.value = {
internalId: "",
releaseTime: moment().format("YYYY-MM-DD HH:mm"),
};
show.value = true;
mode.value = "add";
}
function handleEdit(row) {
formData.value = { ...row };
if (formData.value.files) {
formData.value.files = JSON.parse(formData.value.files);
} else {
formData.value.files = [];
}
show.value = true;
mode.value = "edit";
}
@ -284,6 +349,18 @@ async function submit() {
getList();
feedback.msgSuccess("操作成功");
}
const detailShow = ref(false);
const activeRow = ref({});
function handleShow(row) {
activeRow.value = { ...row };
if (activeRow.value.files) {
activeRow.value.files = JSON.parse(activeRow.value.files);
} else {
activeRow.value.files = [];
}
detailShow.value = true;
}
</script>
<style lang="scss" scoped>
</style>

86
src/views/work/Query.vue

@ -90,7 +90,6 @@
v-model="query.reportNumber"
clearable
/>
</div>
</div>
<div class="form-row flex">
@ -204,7 +203,6 @@
<el-option label="办结超时" :value="true" />
</el-select>
<div class="flex gap-4" style="height: 32px">
<el-select
v-model="query.responderKey"
@ -239,8 +237,6 @@
<el-option label="市局下发" :value="0" />
<el-option label="二级机构下发" :value="2" />
</el-select>
</div>
</div>
</el-form>
@ -249,6 +245,15 @@
>数据导出</el-button
>
<div>
<el-switch
v-model="remainingTimeFlag"
inline-prompt
active-text="显示流程限时"
inactive-text="隐藏流程限时"
:active-value="true"
:inactive-value="false"
class="mr-20"
/>
<el-button type="primary" @click="getList">
<template #icon
><icon name="el-icon-Search"
@ -348,6 +353,7 @@
label="问题来源"
prop="problemSources"
width="110"
show-overflow-tooltip
/>
<el-table-column
label="业务类别"
@ -378,6 +384,7 @@
label="流程限时"
width="150"
align="center"
v-if="remainingTimeFlag"
>
<template #default="{ row }">
<countdown
@ -434,49 +441,79 @@
}}</span>
</template>
</el-table-column>
<el-table-column label="操作" width="220">
<el-table-column label="操作" width="160">
<template #default="{ row }">
<div class="flex v-center">
<el-button
type="primary"
link
@click="handleAction(row)"
>详情</el-button
>
<el-dropdown
trigger="click"
placement="bottom-start"
class="ml-10"
>
<el-button type="primary" link
>更多操作</el-button
>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item>
<el-button
type="primary"
link
text
@click="handleEdit(row)"
v-perms="['negative:edit']"
>编辑</el-button
>
</el-dropdown-item>
<el-dropdown-item>
<el-button
type="danger"
link
text
@click="handleDel(row)"
v-perms="['negative:del']"
>删除</el-button
>
</el-dropdown-item>
<el-dropdown-item>
<el-button
type="primary"
link
@click="handleTransferTodo(row)"
v-perms="['negative:transferTodo']"
text
@click="
handleTransferTodo(row)
"
v-perms="[
'negative:transferTodo',
]"
v-if="
row.processingStatus ===
ProcessingStatus.COMPLETED
"
>转待办</el-button
>
</el-dropdown-item>
<el-dropdown-item>
<el-button
type="primary"
link
text
v-if="
row.processingStatus ===
ProcessingStatus.COMPLETED
"
@click="handleSpotCheck(row)"
@click="
handleSpotCheck(row)
"
v-perms="['negative:spotCheck']"
>抽查</el-button
>
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</template>
</el-table-column>
</el-table>
@ -778,6 +815,7 @@
>
</footer>
</el-dialog>
</template>
<script setup>
import moment from "moment";
@ -805,7 +843,7 @@ const dict = catchStore.getDicts([
"processingStatus",
"suspectProblem",
"policeType",
"specialSupervision",
"specialSupervision"
]);
const flowNodes = catchStore.getFlowNodes();
const dictProblemSources = catchStore.getDictProblemSources();
@ -815,7 +853,7 @@ const query = ref({
current: 1,
size: 10,
responderKey: "name",
blameKey: "name"
blameKey: "name",
});
const list = ref([]);
@ -848,7 +886,7 @@ function reset() {
current: 1,
size: 10,
responderKey: "name",
blameKey: "name"
blameKey: "name",
};
tableRef.value.clearSort();
getList();
@ -858,7 +896,7 @@ function reset() {
const route = useRoute();
watch(
() => route.query,
() => route.query.toString(),
() => {
updateQuery();
getList();
@ -868,21 +906,15 @@ watch(
function updateQuery() {
if (route.query.processingStatus) {
query.value.processingStatus = [route.query.processingStatus];
} else {
query.value.processingStatus = [];
}
if (route.query.crtTime === "today") {
query.value.crtTime = [
moment().startOf("day").format("YYYY-MM-DD HH:mm:ss"),
moment().endOf("day").format("YYYY-MM-DD HH:mm:ss"),
];
} else {
query.value.crtTime = [];
}
if (route.query.extensionFlag === "true") {
query.value.extensionFlag = true;
} else {
query.value.extensionFlag = "";
}
}
@ -957,6 +989,16 @@ function handleSpotCheck(row) {
show.value = true;
negativeDialogRef.value.spotCheck();
}
const remainingTimeFlag = ref(true);
</script>
<style lang="scss" scoped>
:deep() {
.el-dropdown-menu__item {
padding: 0;
.el-button {
width: 100%;
}
}
}
</style>

56
src/views/work/Todo.vue

@ -90,7 +90,6 @@
v-model="query.reportNumber"
clearable
/>
</div>
</div>
<div class="form-row flex">
@ -151,10 +150,13 @@
style="width: 190px"
/>
</div>
<el-select placeholder="处置结果"
<el-select
placeholder="处置结果"
v-model="query.handleResultCode"
clearable
style="width: 280px" multiple>
style="width: 280px"
multiple
>
<el-option
v-for="item in dict.handleResult"
:key="item.id"
@ -242,14 +244,26 @@
</div>
</el-form>
<div class="flex between mt-20 mb-26">
<div>
<el-button
type="primary"
@click="addShow = true"
v-perms="['negative:add']"
><template #icon> <icon name="el-icon-Plus" /> </template
><template #icon>
<icon name="el-icon-Plus" /> </template
>问题下发</el-button
>
</div>
<div>
<el-switch
v-model="remainingTimeFlag"
inline-prompt
active-text="显示流程限时"
inactive-text="隐藏流程限时"
:active-value="true"
:inactive-value="false"
class="mr-20"
/>
<el-button type="primary" @click="getList">
<template #icon
><icon name="el-icon-Search"
@ -300,7 +314,10 @@
<div class="col col-6">
<label>涉嫌问题</label>
<span>{{
getInvolveProblem(row.involveProblem, dict.suspectProblem)
getInvolveProblem(
row.involveProblem,
dict.suspectProblem
)
}}</span>
</div>
</div>
@ -325,7 +342,12 @@
<el-table-column label="业务类别" prop="businessTypeName" />
<el-table-column label="涉嫌问题">
<template #default="{ row }">
<span>{{ getInvolveProblem(row.involveProblem, dict.suspectProblem) }}</span>
<span>{{
getInvolveProblem(
row.involveProblem,
dict.suspectProblem
)
}}</span>
</template>
</el-table-column>
<el-table-column
@ -360,15 +382,21 @@
dict.processingStatus,
row.processingStatus
)
}}{{ row.extensionApplyFlag ? "" : "(延期申请)"
}}{{
row.extensionApplyFlag ? "" : "(延期申请)"
}}{{
row.workFlowKey === 'countersign' ? "(单位会签)" : ""
row.workFlowKey === "countersign"
? "(单位会签)"
: ""
}}</el-tag
>
</template>
</el-table-column>
<el-table-column label="流程限时" width="150" align="center">
<el-table-column
label="流程限时"
width="150"
align="center"
v-if="remainingTimeFlag"
>
<template #default="{ row }">
<countdown
:time="row.remainingDuration"
@ -408,7 +436,8 @@
</el-table-column>
</el-table>
</div>
<div class="flex end mt-8">
<div class="flex between v-center mt-8">
<div>说明待办列表展示当前需要本人待办的工作已办结/已审批问题请前往 <span class="link pointer" @click="router.push('/query')">综合查询</span>列表查看</div>
<el-pagination
@size-change="getList"
@current-change="getList"
@ -420,6 +449,7 @@
>
</el-pagination>
</div>
</div>
<negative-dialog
@ -445,7 +475,9 @@ const dict = catchStore.getDicts([
"processingStatus",
"inspectCase",
"handleResult",
"isRectify"
]);
const router = useRouter()
const flowNodes = catchStore.getFlowNodes();
const dictProblemSources = catchStore.getDictProblemSources();
@ -490,6 +522,8 @@ function handleAction(row) {
}
const addShow = ref(false);
const remainingTimeFlag = ref(true);
</script>
<style lang="scss" scoped>
</style>

1813
src/views/work/VerifySubmit.vue

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save