index.vue 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920
  1. <template>
  2. <home-container>
  3. <view class="report-container">
  4. <!-- 表单区域 -->
  5. <uni-forms ref="form" :rules="rules" :modelValue="formData" label-position="top" err-show-type="modal">
  6. <!-- 1. 基本信息分组 (默认展开) -->
  7. <view class="card">
  8. <uni-collapse :accordion="false" :value="['group1']">
  9. <h-collapse-item title="基本信息" name="group1" :show-animation="true"
  10. :iconUrl="'../../static/images/icon/jiben.png'">
  11. <uni-forms-item label="任务编号" name="taskCode">
  12. <uni-easyinput v-model="formData.taskCode" placeholder="系统自动生成" disabled />
  13. </uni-forms-item>
  14. <uni-forms-item label="巡检编号" name="documentCode">
  15. <uni-easyinput v-model="formData.documentCode" placeholder="系统自动生成" disabled />
  16. </uni-forms-item>
  17. <uni-forms-item label="检查人" name="checkerName">
  18. <uni-easyinput v-model="formData.checkerName" placeholder="请输入检查人姓名" disabled />
  19. </uni-forms-item>
  20. <uni-forms-item :label="getCheckLabel" name="checkedDepartmentId">
  21. <uni-data-picker v-if="getCheckLabel == '被检查科'" :localdata="departments"
  22. :popup-title="`请选择${getCheckLabel}`" v-model="formData.checkedDepartmentId"
  23. :readonly="true" />
  24. <uni-data-picker v-if="getCheckLabel == '被检查大队'" :localdata="brigades"
  25. :popup-title="`请选择${getCheckLabel}`" v-model="formData.checkedBrigadeId"
  26. :readonly="true" />
  27. <uni-data-picker v-if="getCheckLabel == '被检查班组'" :localdata="teams"
  28. :popup-title="`请选择${getCheckLabel}`" v-model="formData.checkedTeamId"
  29. :readonly="true" />
  30. <fuzzy-select v-if="getCheckLabel == '被检查人'" v-model="formData.checkedPersonnelId"
  31. :options="userOptions" placeholder="请输入被检查人姓名搜索" data-value="userId"
  32. data-text="nickName" disabled />
  33. </uni-forms-item>
  34. <uni-forms-item label="检查时间" name="checkTime">
  35. <uni-datetime-picker type="datetime" :start="startDate" :end="endDate"
  36. v-model="formData.checkTime" disabled />
  37. </uni-forms-item>
  38. <uni-forms-item label="检查位置" name="checkLocation">
  39. <uni-easyinput v-model="formData.checkLocation" placeholder="请选择检查位置" disabled />
  40. </uni-forms-item>
  41. </h-collapse-item>
  42. </uni-collapse>
  43. </view>
  44. <!-- 2. 待整改问题分组 -->
  45. <view class="card">
  46. <uni-collapse :accordion="false" :value="['group2']">
  47. <h-collapse-item title="待整改问题" name="group2" :show-animation="true"
  48. :iconUrl="'../../static/images/icon/wenti.png'">
  49. <view style="padding: 0 15px 15px 15px;">
  50. <!-- 问题列表遍历 -->
  51. <view v-for="(problem, index) in formData.checkProjectItemList" :key="problem.id"
  52. class="problem-item">
  53. <view class="problem-header">
  54. <text class="problem-title">{{
  55. `${problem.categoryNameOne}/${problem.categoryNameTwo}/${problem.projectName}`
  56. }}</text>
  57. </view>
  58. <view class="problem-content">
  59. <view class="problem-person">
  60. <view class="problem-label"><text v-if="isResponsiblePerson"
  61. style="color: red;">*</text>问题人<text
  62. style="color: red;margin-left: 10rpx;">请确定问题人</text></view>
  63. <fuzzy-select :value="getCheckUserListValue(problem.checkUserList)"
  64. :options="userOptions" :placeholder="'请输入问题' + (index + 1) + '的责任人'"
  65. data-value="userId" data-text="nickName"
  66. @input="handleUserInput(index, $event)"
  67. @change="handleUserSelect($event, index)"
  68. @delete="handleUserDelete(index)" :disabled="formDisabled" />
  69. </view>
  70. <view class="problem-description">
  71. <text class="problem-label">问题描述</text>
  72. <uni-easyinput type="textarea" v-model="problem.problemDescription"
  73. :disabled="true" />
  74. </view>
  75. </view>
  76. </view>
  77. <uni-file-picker v-if="formData.checkRecordBaseAttachmentList.length > 0"
  78. v-model="formData.checkRecordBaseAttachmentList" limit="8" title="最多上传8张"
  79. :image-styles="imageStyles" fileMediatype="image" mode="grid"
  80. @select="onCheckRecordBaseAttachmentListSelect" :disabled="true" :del-icon="false"
  81. :readonly="true" />
  82. </view>
  83. </h-collapse-item>
  84. </uni-collapse>
  85. </view>
  86. <!-- 3. 整改要求分组 -->
  87. <view class="card">
  88. <uni-collapse :accordion="false" :value="['group3']">
  89. <h-collapse-item title="整改要求" name="group3" :show-animation="true"
  90. :iconUrl="'../../static/images/icon/yaoqiu.png'">
  91. <uni-forms-item label="责任人" name="responsibleUserName" required>
  92. <uni-easyinput v-model="formData.responsibleUserName" placeholder="请输入责任人姓名" disabled />
  93. </uni-forms-item>
  94. <uni-forms-item label="整改期限" name="rectificationDeadline" required>
  95. <uni-datetime-picker type="datetime" :start="startDate" :end="endDate"
  96. v-model="formData.rectificationDeadline" disabled />
  97. </uni-forms-item>
  98. <!-- 是否流转至班组 -->
  99. <uni-forms-item
  100. v-if="nodeCode === 'SECTION_LEADER_APPROVE' && businessType === 'SECTION_CHECK'"
  101. label="是否流转至班组" name="isSelectTeam">
  102. <radio-group @change="handleIsSelectTeamChange" class="radio-group">
  103. <label class="radio-item">
  104. <radio :value="'0'" :checked="formData.isSelectTeam == 0" color="#409EFF" />
  105. <text>否</text>
  106. </label>
  107. <label class="radio-item">
  108. <radio :value="'1'" :checked="formData.isSelectTeam == 1" color="#409EFF" />
  109. <text>是</text>
  110. </label>
  111. </radio-group>
  112. </uni-forms-item>
  113. <!-- 整改班组 -->
  114. <uni-forms-item
  115. v-if="nodeCode === 'SECTION_LEADER_APPROVE' && businessType === 'SECTION_CHECK' && formData.isSelectTeam == 1"
  116. label="整改班组" name="selectTeamId">
  117. <uni-data-picker :localdata="teams" popup-title="请选择整改班组"
  118. v-model="formData.selectTeamId" @change="handlecheckedTeamIdChange" />
  119. </uni-forms-item>
  120. <!-- 班组长 -->
  121. <uni-forms-item
  122. v-if="nodeCode === 'SECTION_LEADER_APPROVE' && businessType === 'SECTION_CHECK' && formData.isSelectTeam == 1"
  123. label="班组长" name="selectTeamLeaderName">
  124. <uni-easyinput v-model="formData.selectTeamLeaderName" placeholder="班组长" disabled />
  125. </uni-forms-item>
  126. <uni-forms-item label="整改要求" name="rectificationSuggestions">
  127. <uni-easyinput type="textarea" v-model="formData.rectificationSuggestions"
  128. placeholder="请输入整改要求" disabled />
  129. </uni-forms-item>
  130. </h-collapse-item>
  131. </uni-collapse>
  132. </view>
  133. <!-- 4. 整改信息分组 -->
  134. <view class="card">
  135. <uni-collapse :accordion="false" :value="['group4']">
  136. <h-collapse-item title="整改信息" name="group4" :show-animation="true"
  137. :iconUrl="'../../static/images/icon/zhenggai.png'">
  138. <uni-forms-item label="整改详情" name="rectificationDetails"
  139. :required="rectificationDetailsRequired">
  140. <uni-easyinput type="textarea" v-model="formData.rectificationDetails"
  141. placeholder="请输入整改详情" :disabled="formDisabled" />
  142. </uni-forms-item>
  143. <view style="padding: 0 15px 15px 15px;">
  144. <uni-file-picker v-model="formData.baseAttachmentList" limit="8" title="最多上传8张整改照片"
  145. :image-styles="imageStyles" fileMediatype="image" mode="grid"
  146. @select="onBaseAttachmentListelect" :disabled="formDisabled"
  147. :del-icon="!formDisabled" :readonly="formDisabled" />
  148. </view>
  149. </h-collapse-item>
  150. </uni-collapse>
  151. </view>
  152. <!-- 5. 审批历史分组 -->
  153. <view class="card">
  154. <uni-collapse :accordion="false" :value="['group5']">
  155. <h-collapse-item title="审批历史" name="group5" :show-animation="true"
  156. :iconUrl="'../../static/images/icon/lishi.png'">
  157. <approve-history :history-list="approvalHistory" />
  158. </h-collapse-item>
  159. </uni-collapse>
  160. </view>
  161. <!-- 提交按钮 -->
  162. <view class="button-group" v-if="type === 'approve'">
  163. <!-- <view v-if="btnPermission.showSubmitBtn" class="custom-btn-normal" @click="submitForm">立刻提交
  164. </view> -->
  165. <RejectModal v-if="btnPermission.showApproveRejectBtn" @confirm="handleRejectConfirm">
  166. <view class="custom-btn-white">
  167. 驳回/退回
  168. </view>
  169. </RejectModal>
  170. <view v-if="btnPermission.showApprovePassBtn" class="custom-btn-normal" @click="submitForm">{{
  171. nodeCode == 'START' ? '提交' : '通过/提交' }}
  172. </view>
  173. </view>
  174. </uni-forms>
  175. </view>
  176. </home-container>
  177. </template>
  178. <script>
  179. import HomeContainer from "@/components/HomeContainer.vue";
  180. import { treeSelectByType } from "@/api/system/common"
  181. import { uploadFile } from '@/utils/common'
  182. import useDictMixin from '@/utils/dict'
  183. import RejectModal from './components/RejectModal.vue'
  184. import { addChecklistRecord } from '@/api/check/checklist.js'
  185. import config from '@/config'
  186. import { getToken } from '@/utils/auth'
  187. import { checkedLevelEnums } from "@/utils/enums.js"
  188. import { getDeptList } from "@/api/system/dept/dept.js"
  189. import { selectDeptLeaderByUserId } from '@/api/approve/approve.js'
  190. import { formatTime } from '@/utils/formatUtils'
  191. import { listAllUser } from "@/api/system/user.js"
  192. import { getProblemRectDetail, approvalAgree, approvalReject } from '@/api/problemRect/problemRect.js'
  193. import { getApprovelHistory } from '@/api/approve/approve.js'
  194. import { getDeptManager, getDeptDetail } from "@/api/system/dept/dept.js"
  195. import { buildTeamOptions, buildDepartmentOptions, buildBrigadeOptions } from "@/utils/common.js"
  196. export default {
  197. components: { HomeContainer, RejectModal },
  198. mixins: [useDictMixin],
  199. computed: {
  200. currentUser() {
  201. return this.$store.state.user;
  202. },
  203. currentUserId() {
  204. return this.currentUser && this.currentUser.id;
  205. },
  206. //表单责任人是当前登陆人
  207. isResponsiblePerson() {
  208. return this.currentUserId == this.formData.responsibleUserId;
  209. },
  210. userInfo() {
  211. return (this.$store.state.user && this.$store.state.user.userInfo) ? this.$store.state.user.userInfo : {}
  212. },
  213. userInfoRoles() {
  214. return this.$store.state.user && this.$store.state.user.roles
  215. },
  216. // 按钮权限判断
  217. btnPermission() {
  218. const roles = this.userInfoRoles || [];
  219. return {
  220. // 班组长或安全检查员显示"立刻提交"按钮
  221. showApprovePassBtn: ['SECTION_LEADER_APPROVE', 'GROUP_LEADER_RECTIFY', 'INITIATOR_FINAL_REVIEW', 'RESPONSIBLE_PERSON_REVIEW'].includes(this.nodeCode) || (this.businessType == 'PERSONAL_CHECK' && ['INITIATOR_REVIEW', 'PROBLEM_USER_RECTIFY'].includes(this.nodeCode)) || (this.businessType == 'GROUP_CHECK' && ['SECTION_REVIEW'].includes(this.nodeCode)) || this.nodeCode == 'START',
  222. showApproveRejectBtn: ['GROUP_LEADER_RECTIFY', 'INITIATOR_FINAL_REVIEW', 'RESPONSIBLE_PERSON_REVIEW'].includes(this.nodeCode) || (this.businessType == 'PERSONAL_CHECK' && ['INITIATOR_REVIEW', 'SECTION_LEADER_APPROVE'].includes(this.nodeCode)) || (this.businessType == 'GROUP_CHECK' && ['SECTION_REVIEW'].includes(this.nodeCode)),
  223. };
  224. },
  225. formDisabled() {
  226. return this.type === 'view';
  227. },
  228. getCheckLabel() {
  229. if (this.formData.checkedLevel == checkedLevelEnums.TEAM_LEVEL) {
  230. return '被检查班组'
  231. }
  232. if (this.formData.checkedLevel == checkedLevelEnums.PERSONNEL_LEVEL) {
  233. // this.getDeptLeader()
  234. return '被检查人'
  235. }
  236. if (this.formData.checkedLevel == checkedLevelEnums.DEPARTMENT_LEVEL) {
  237. return '被检查科'
  238. }
  239. if (this.formData.checkedLevel == checkedLevelEnums.BRIGADE_LEVEL) {
  240. return '被检查大队'
  241. }
  242. },
  243. // 动态验证规则
  244. rules() {
  245. return {
  246. checkerName: {
  247. rules: [{ required: true, errorMessage: '请输入检查人姓名' }]
  248. },
  249. checkTime: {
  250. rules: [{ required: true, errorMessage: '请选择检查时间' }]
  251. },
  252. checkLocation: {
  253. rules: [{ required: true, errorMessage: '请选择检查位置' }]
  254. },
  255. rectificationDetails: {
  256. rules: this.rectificationDetailsRequired ? [{ required: true, errorMessage: '请输入整改详情' }] : []
  257. },
  258. isSelectTeam: {
  259. rules: [{ required: true, errorMessage: '请选择是否流转至班组' }]
  260. },
  261. selectTeamId: {
  262. rules: [{ required: true, errorMessage: '请选择整改班组' }]
  263. }
  264. };
  265. },
  266. rectificationDetailsRequired() {
  267. //科长并且是责任人节点,并且是否流转至班组长为是,整改详情不必填,为否,整改详情必填;或者是班组长节点,也必填
  268. let res1 = this.formData.checkedLevel == 'DEPARTMENT_LEVEL' && ((this.nodeCode == 'SECTION_LEADER_APPROVE' && this.formData.isSelectTeam !== 1) || this.nodeCode == 'GROUP_LEADER_RECTIFY');
  269. // 班组长并且是责任人节点,必填
  270. let res2 = this.formData.checkedLevel == 'TEAM_LEVEL' && this.nodeCode == 'GROUP_LEADER_RECTIFY';
  271. //个人
  272. let res3 = this.formData.checkedLevel == 'PERSONNEL_LEVEL' && this.nodeCode == 'PROBLEM_USER_RECTIFY';
  273. return res1 || res2 || res3 || this.isResponsiblePerson
  274. },
  275. },
  276. data() {
  277. return {
  278. userOptions: [],
  279. teams: [], // 班组选项数据
  280. departments: [], // 部门选项数据
  281. brigades: [], // 大队选项数据
  282. // 表单数据
  283. formData: {
  284. // 基本信息
  285. taskCode: "",
  286. checkerName: '',
  287. checkLocation: '',
  288. // 待整改问题
  289. baseAttachmentList: [],
  290. checkRecordBaseAttachmentList: [],
  291. // 整改要求
  292. responsibleUserName: '',
  293. rectificationDeadline: '',
  294. rectificationSuggestions: '',
  295. isSelectTeam: 0, // 是否流转至班组 0-否 1-是
  296. selectTeamId: '', // 整改班组ID
  297. selectTeamName: '', // 整改班组名称
  298. selectTeamLeaderId: '', // 班组长ID
  299. selectTeamLeaderName: '', // 班组长姓名
  300. // 被检查对象相关字段
  301. checkedBrigadeId: '', // 被检查大队ID
  302. checkedBrigadeName: '', // 被检查大队名称
  303. // 整改信息
  304. rectificationDetails: '',
  305. baseAttachmentList: []
  306. },
  307. // 审批历史数据
  308. approvalHistory: [],
  309. // 数据选项
  310. location_options: [],
  311. // 其他数据
  312. startDate: '2020-01-01',
  313. endDate: '2030-12-31',
  314. imageStyles: {
  315. width: 80,
  316. height: 80,
  317. border: {
  318. color: '#eee',
  319. width: '1px',
  320. style: 'solid'
  321. }
  322. },
  323. dataOptionMap: { text: 'label', value: 'value' },
  324. businessId: '',
  325. instanceId: '',
  326. id: '',
  327. nodeCode: '',
  328. type: '',
  329. businessType: '',
  330. }
  331. },
  332. onLoad(options) {
  333. let params = JSON.parse(decodeURIComponent(options.params));
  334. this.businessId = params.businessId;
  335. this.instanceId = params.instanceId;
  336. this.id = params.id;
  337. this.nodeCode = params.nodeCode;
  338. this.type = params.type;
  339. this.businessType = params.businessType;
  340. this.initPageData();
  341. },
  342. mounted() {
  343. this.loadDictData();
  344. console.log(this.$store.state.user)
  345. },
  346. methods: {
  347. handleUserSelect(e, index) {
  348. const person = this.userOptions.find(item => item.userId == e)
  349. if (this.formData.checkProjectItemList && this.formData.checkProjectItemList[index]) {
  350. this.formData.checkProjectItemList[index].checkUserList = person;
  351. }
  352. },
  353. // 获取checkUserList的值,处理null情况
  354. getCheckUserListValue(checkUserList) {
  355. return checkUserList && checkUserList.userId ? checkUserList.userId : '';
  356. },
  357. // 处理用户输入
  358. handleUserInput(index, value) {
  359. if (this.formData.checkProjectItemList && this.formData.checkProjectItemList[index]) {
  360. if (!this.formData.checkProjectItemList[index].checkUserList) {
  361. this.formData.checkProjectItemList[index].checkUserList = {};
  362. }
  363. this.formData.checkProjectItemList[index].checkUserList.userId = value;
  364. }
  365. },
  366. // 处理用户删除
  367. handleUserDelete(index) {
  368. // 将problem.checkUserList置为null
  369. if (this.formData.checkProjectItemList && this.formData.checkProjectItemList[index]) {
  370. this.formData.checkProjectItemList[index].checkUserList = null;
  371. // 强制更新视图以确保fuzzy-select组件重新渲染
  372. this.$nextTick(() => {
  373. this.$forceUpdate();
  374. });
  375. }
  376. },
  377. // 被检查大队选择
  378. handlecheckedBrigadeIdChange(e) {
  379. const { text, value } = e.detail.value[0];
  380. let newText = text.split('/')
  381. this.$set(this.formData, 'checkedBrigadeName', newText[newText.length - 1].trim());
  382. this.$set(this.formData, 'checkedBrigadeId', value);
  383. },
  384. async loadDictData() {
  385. const user = await listAllUser();
  386. this.userOptions = user.data.map(item => ({
  387. ...item,
  388. nickName: `${item.nickName}(${item.userName})`,
  389. })) || [];
  390. },
  391. async initPageData() {
  392. try {
  393. uni.showLoading({ title: '加载中...', mask: true });
  394. // 如果有ID,获取问题整改详细信息
  395. if (this.businessId) {
  396. const detailRes = await getProblemRectDetail(this.businessId);
  397. if (detailRes.code === 200 && detailRes.data) {
  398. this.fillFormData(detailRes.data);
  399. }
  400. // 获取审批历史
  401. const historyRes = await getApprovelHistory(this.instanceId);
  402. if (historyRes.code === 200 && historyRes.rows) {
  403. this.approvalHistory = historyRes.rows;
  404. }
  405. }
  406. // 获取位置列表
  407. const positionRes = await treeSelectByType("POSITION", 3);
  408. this.location_options = this.convertTree(positionRes.data || []);
  409. // 获取班组列表
  410. const deptTree = await getDeptList();
  411. this.teams = buildTeamOptions(deptTree.data || []);
  412. this.departments = buildDepartmentOptions(deptTree.data || []);
  413. this.brigades = buildBrigadeOptions(deptTree.data || []);
  414. uni.hideLoading();
  415. } catch (err) {
  416. uni.hideLoading();
  417. uni.showToast({ title: '加载失败', icon: 'none' });
  418. console.error('初始化数据失败:', err);
  419. }
  420. },
  421. // 填充表单数据
  422. async fillFormData(data) {
  423. console.log(data, "data")
  424. // debugger
  425. let checedProjectArr = [];
  426. if (data.checkProjectItemList && data.checkProjectItemList?.length > 0) {
  427. if (this.businessType == 'PERSONAL_CHECK' && this.nodeCode == 'SECTION_LEADER_APPROVE') {
  428. // let res = await selectDeptLeaderByUserId({
  429. // userId: data.checkedPersonnelId,
  430. // deptType: 'TEAMS'
  431. // })
  432. // let dept = {}
  433. // if (res.code == 200) {
  434. // dept = res.data || {};
  435. // }
  436. // let res1 = await getDeptDetail(dept.deptId)
  437. // if (res1.code == 200) {
  438. // console.log(res1, "res1")
  439. // debugger
  440. // }
  441. data.checkProjectItemList = data.checkProjectItemList.map(item => ({
  442. ...item,
  443. checkUserList: [{ userName: data.checkedPersonnelName, userId: data.checkedPersonnelId, }]
  444. }))
  445. console.log(data.checkProjectItemList, "data.checkProjectItemList")
  446. data.checkProjectItemList.forEach(element => {
  447. if (element.checkUserList && element.checkUserList?.length > 0) {
  448. element.checkUserList.forEach(user => {
  449. checedProjectArr.push({
  450. ...element,
  451. checkUserList: user
  452. })
  453. });
  454. }
  455. });
  456. } else {
  457. data.checkProjectItemList.forEach(element => {
  458. if (element.checkUserList && element.checkUserList?.length > 0) {
  459. element.checkUserList.forEach(user => {
  460. checedProjectArr.push({
  461. ...element,
  462. checkUserList: user
  463. })
  464. });
  465. } else {
  466. checedProjectArr.push({
  467. ...element,
  468. checkUserList: { userId: "" }
  469. })
  470. }
  471. });
  472. }
  473. }
  474. console.log(checedProjectArr, "checedProjectArr")
  475. // debugger
  476. this.formData = {
  477. ...this.formData,
  478. ...data,
  479. checkLocation: `${data.terminlName}/${data.regionalName}/${data.channelName}`,
  480. baseAttachmentList: data.baseAttachmentList?.length ? data.baseAttachmentList.map(img => ({
  481. ...img,
  482. url: img.attachmentUrl || img.url,
  483. name: img.attachmentName || img.name,
  484. extname: img.extname || (img.name ? img.name.split('.').pop() : '')
  485. })) : [],
  486. baseAttachmentList: (data.baseAttachmentList && data.baseAttachmentList?.length > 0) ? data.baseAttachmentList.map(img => ({
  487. ...img,
  488. url: img.attachmentUrl || img.url,
  489. name: img.attachmentName || img.name,
  490. extname: img.extname || (img.name ? img.name.split('.').pop() : '')
  491. })) : [],
  492. checkProjectItemList: checedProjectArr,
  493. approvalHistory: (data.approvalHistory && data.approvalHistory?.length > 0) ? data.approvalHistory.map(item => ({
  494. name: item.name || '未知用户',
  495. date: item.date || new Date().toISOString().split('T')[0],
  496. content: item.content || '无审批内容'
  497. })) : [],
  498. }
  499. },
  500. convertTree(list = []) {
  501. return list.map(node => ({
  502. text: node.label,
  503. value: node.code,
  504. children: node.children ? this.convertTree(node.children) : null
  505. }));
  506. },
  507. // 选择待整改问题图片
  508. async onBaseAttachmentListelect(event) {
  509. const file = await uploadFile(event);
  510. this.formData.baseAttachmentList.push({
  511. url: file.url,
  512. name: file.newFileName,
  513. attachmentName: file.newFileName,
  514. attachmentUrl: file.url,
  515. extname: file.newFileName.split('.').pop()
  516. });
  517. },
  518. // 选择不合格图片
  519. async onCheckRecordBaseAttachmentListSelect(event) {
  520. const file = await uploadFile(event);
  521. this.formData.checkRecordBaseAttachmentList.push({
  522. url: file.url,
  523. name: file.newFileName,
  524. attachmentName: file.newFileName,
  525. attachmentUrl: file.url,
  526. extname: file.newFileName.split('.').pop()
  527. });
  528. },
  529. formatDateTime(date) {
  530. const y = date.getFullYear();
  531. const m = String(date.getMonth() + 1).padStart(2, '0');
  532. const d = String(date.getDate()).padStart(2, '0');
  533. const h = String(date.getHours()).padStart(2, '0');
  534. const mm = String(date.getMinutes()).padStart(2, '0');
  535. const s = String(date.getSeconds()).padStart(2, '0');
  536. return `${y}-${m}-${d} ${h}:${mm}:${s}`;
  537. },
  538. handleRejectConfirm(reason) {
  539. this.formData.comment = reason
  540. this.rejectForm()
  541. },
  542. rejectForm() {
  543. // this.$refs.form.validate().then(res => {
  544. uni.showLoading({ title: '提交中...', mask: true });
  545. // 还原checkProjectItemList结构到后端原始格式
  546. const restoredCheckProjectItemList = this.restoreOriginalCheckProjectItemList();
  547. const payload = {
  548. ...this.formData,
  549. checkProjectItemList: restoredCheckProjectItemList,
  550. taskId: this.id,
  551. instanceId: this.instanceId,
  552. };
  553. approvalReject(payload)
  554. .then(() => {
  555. uni.showToast({ title: '提交成功', icon: 'success' });
  556. setTimeout(() => uni.navigateBack(), 1500);
  557. })
  558. .catch((error) => {
  559. uni.showToast({ title: '操作失败,请稍后重试!', icon: 'none' });
  560. console.error('提交失败:', error);
  561. });
  562. // }).catch(err => {
  563. // console.log('表单验证失败:', err);
  564. // });
  565. },
  566. // 提交表单
  567. submitForm() {
  568. debugger
  569. // 如果当前用户是责任人,校验问题人字段必填
  570. if (this.isResponsiblePerson) {
  571. const hasEmptyProblemUser = this.formData.checkProjectItemList?.some(problem =>
  572. !problem.checkUserList || !problem.checkUserList.userId
  573. );
  574. if (hasEmptyProblemUser) {
  575. uni.showToast({
  576. title: '请填写所有问题的问题人',
  577. icon: 'none',
  578. duration: 3000
  579. });
  580. return;
  581. }
  582. }
  583. this.$refs.form.validate().then(res => {
  584. uni.showLoading({ title: '提交中...', mask: true });
  585. // 还原checkProjectItemList结构到后端原始格式
  586. const restoredCheckProjectItemList = this.restoreOriginalCheckProjectItemList();
  587. const payload = {
  588. ...this.formData,
  589. checkProjectItemList: restoredCheckProjectItemList,
  590. taskId: this.id,
  591. instanceId: this.instanceId,
  592. comment: '审批通过'
  593. };
  594. approvalAgree(payload)
  595. .then(() => {
  596. uni.showToast({ title: '提交成功', icon: 'success' });
  597. setTimeout(() => uni.navigateBack(), 1500);
  598. })
  599. .catch((error) => {
  600. uni.showToast({ title: '操作失败,请稍后重试!', icon: 'none' });
  601. console.error('提交失败:', error);
  602. });
  603. }).catch(err => {
  604. console.log('表单验证失败:', err);
  605. });
  606. },
  607. // 处理是否流转至班组选择
  608. handleIsSelectTeamChange(e) {
  609. const selectedValue = parseInt(e.detail.value);
  610. this.$set(this.formData, 'isSelectTeam', selectedValue);
  611. // 如果选择"否",清空班组相关字段
  612. if (selectedValue === 0) {
  613. this.$set(this.formData, 'selectTeamId', '');
  614. this.$set(this.formData, 'selectTeamName', '');
  615. this.$set(this.formData, 'selectTeamLeaderId', '');
  616. this.$set(this.formData, 'selectTeamLeaderName', '');
  617. }
  618. },
  619. // 处理整改班组选择
  620. handlecheckedTeamIdChange(e) {
  621. const { text, value } = e.detail.value[0];
  622. this.$set(this.formData, 'selectTeamName', text);
  623. this.$set(this.formData, 'selectTeamId', value);
  624. // 获取班组长信息
  625. getDeptManager(value).then(res => {
  626. console.log(res?.data?.userId, "班组长信息");
  627. this.$set(this.formData, 'selectTeamLeaderId', res?.data?.userId || '');
  628. this.$set(this.formData, 'selectTeamLeaderName', res?.data?.nickName || '');
  629. }).catch(err => {
  630. console.error('获取班组长信息失败:', err);
  631. this.$set(this.formData, 'selectTeamLeaderId', '');
  632. this.$set(this.formData, 'selectTeamLeaderName', '');
  633. });
  634. },
  635. // 还原checkProjectItemList到后端原始格式
  636. restoreOriginalCheckProjectItemList() {
  637. const groupedItems = {};
  638. // 按照原始问题项分组
  639. this.formData.checkProjectItemList?.forEach(item => {
  640. const key = `${item.categoryCodeOne}-${item.categoryCodeTwo}-${item.problemDescription}`;
  641. if (!groupedItems[key]) {
  642. groupedItems[key] = {
  643. ...item,
  644. checkUserList: []
  645. };
  646. }
  647. // 将用户对象添加到checkUserList数组中
  648. if (item.checkUserList && typeof item.checkUserList === 'object') {
  649. groupedItems[key].checkUserList.push(item.checkUserList);
  650. }
  651. });
  652. return Object.values(groupedItems);
  653. }
  654. }
  655. }
  656. </script>
  657. <style lang="scss" scoped>
  658. .report-container {
  659. min-height: 100vh;
  660. padding-top: 35px;
  661. .card {
  662. border-radius: 8px;
  663. margin: 15px 0;
  664. overflow: hidden;
  665. box-shadow: rgba(0, 0, 0, 0.08) 0px 0px 3px 1px;
  666. }
  667. }
  668. /* 折叠面板标题 */
  669. .collapse-title {
  670. display: flex;
  671. flex-direction: column;
  672. padding: 12px 15px;
  673. .collapse-summary {
  674. font-size: 12px;
  675. color: #999;
  676. margin-top: 4px;
  677. }
  678. }
  679. /* 表单项样式 */
  680. ::v-deep .uni-forms-item {
  681. margin-bottom: 0;
  682. padding: 0 15px;
  683. .uni-forms-item__label {
  684. padding: 12px 0 8px;
  685. font-size: 14px;
  686. color: #666;
  687. width: auto !important;
  688. }
  689. .uni-forms-item__content {
  690. padding: 0 0 12px;
  691. border-bottom: 1px solid #f0f0f0;
  692. }
  693. &:last-child .uni-forms-item__content {
  694. border-bottom: none;
  695. }
  696. }
  697. /* 审批历史样式 */
  698. .approval-history {
  699. padding: 15px;
  700. .approval-item {
  701. display: flex;
  702. // margin-bottom: 20px;
  703. &:last-child {
  704. margin-bottom: 0;
  705. }
  706. .timeline {
  707. display: flex;
  708. flex-direction: column;
  709. align-items: center;
  710. margin-right: 12px;
  711. .circle {
  712. width: 12px;
  713. height: 12px;
  714. border-radius: 50%;
  715. background-color: #409EFF;
  716. border: 2px solid #fff;
  717. box-shadow: 0 0 0 2px #409EFF;
  718. }
  719. .line {
  720. width: 2px;
  721. flex: 1;
  722. background-color: #409EFF;
  723. margin-top: 4px;
  724. }
  725. }
  726. .content {
  727. flex: 1;
  728. position: relative;
  729. bottom: 8rpx;
  730. .header {
  731. display: flex;
  732. justify-content: space-between;
  733. align-items: center;
  734. margin-bottom: 8px;
  735. .name {
  736. font-size: 14px;
  737. font-weight: 500;
  738. color: #333;
  739. }
  740. .date {
  741. font-size: 12px;
  742. color: #999;
  743. }
  744. }
  745. .approval-content {
  746. font-size: 13px;
  747. color: #666;
  748. border: 1px solid #DDDDDD;
  749. line-height: 1.5;
  750. background-color: #f8f9fa;
  751. padding: 10px;
  752. border-radius: 6px;
  753. }
  754. }
  755. }
  756. }
  757. .submit-btn {
  758. margin-top: 20px;
  759. width: calc(100% - 30px);
  760. margin-left: 15px;
  761. }
  762. /* 底部弹窗样式调整 */
  763. ::v-deep .uni-popup__wrapper {
  764. border-radius: 16px 16px 0 0;
  765. .uni-popup__wrapper-box {
  766. max-height: 70vh;
  767. overflow-y: auto;
  768. }
  769. .uni-data-pickerview {
  770. padding-bottom: 20px;
  771. }
  772. }
  773. /* 按钮组样式 - 左右布局 */
  774. .button-group {
  775. display: flex;
  776. justify-content: space-between;
  777. align-items: center;
  778. padding: 0 15px;
  779. margin-top: 20px;
  780. gap: 15px;
  781. }
  782. .button-group .custom-btn-white,
  783. .button-group .custom-btn-normal {
  784. flex: 1;
  785. margin-top: 0;
  786. width: auto;
  787. }
  788. /* 问题列表样式 */
  789. .problem-item {
  790. margin-bottom: 20px;
  791. padding-bottom: 15px;
  792. border-bottom: 1px dashed #e0e0e0;
  793. }
  794. .problem-item:last-child {
  795. border-bottom: none;
  796. margin-bottom: 15px;
  797. }
  798. .problem-header {
  799. margin-bottom: 12px;
  800. }
  801. .problem-title {
  802. font-size: 16px;
  803. font-weight: 600;
  804. color: #626FF0;
  805. }
  806. .problem-content {}
  807. .problem-person,
  808. .problem-description {
  809. margin-bottom: 12px;
  810. }
  811. .problem-label {
  812. display: block;
  813. font-size: 14px;
  814. color: #606266;
  815. margin-bottom: 6px;
  816. font-weight: 500;
  817. }
  818. .problem-description ::v-deep .uni-textarea__textarea {
  819. background-color: #f5f7fa !important;
  820. color: #909399 !important;
  821. cursor: not-allowed !important;
  822. }
  823. </style>