综合办公系统
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022
  1. <template>
  2. <view class="form-container">
  3. <!-- 表单标题 -->
  4. <view class="form-title">
  5. <text class="title-text">设备申请表</text>
  6. <view class="title-line"></view>
  7. </view>
  8. <!-- 表单内容 -->
  9. <uni-forms ref="form" :modelValue="form" :rules="rules" label-position="top" label-width="150" class="custom-form">
  10. <flow-note :taskForm="taskForm"></flow-note>
  11. <!-- 当前节点 -->
  12. <uni-forms-item label="当前节点" class="form-item" v-if="taskName">
  13. <uni-tag :inverted="true" type="primary" :text="taskName"></uni-tag>
  14. </uni-forms-item>
  15. <!-- 流程发起人 -->
  16. <uni-forms-item label="填报人" class="form-item">
  17. <b style="font-size:30rpx;">{{ applierUserName }}</b>
  18. </uni-forms-item>
  19. <!-- 填报日期 -->
  20. <uni-forms-item label="填报日期" class="form-item">
  21. <text>{{ form.applyDate }}</text>
  22. </uni-forms-item>
  23. <!-- 选择项目 -->
  24. <uni-forms-item label="选择项目" class="form-item" name="projectId">
  25. <view v-if="taskName == '设备申请'" style="display: flex; align-items: center; margin-bottom: 10px;">
  26. <uni-icons type="info" size="16" color="#666"></uni-icons>
  27. <text style="font-size: 24rpx; color: #666;">项目非必选,非项目设备申请时,可不选项目</text>
  28. </view>
  29. <uv-button type="primary" @click="openProject = true" v-if="taskName == '设备申请'">+ 选择项目</uv-button>
  30. <ProjectPicker :visible.sync="openProject" :selected.sync="selectedProject" @confirm="handleConfirm" />
  31. <ProjectInfo :project="projectObj" v-if="form.projectId != '0'"></ProjectInfo>
  32. <view v-if="form.projectId == '0' && taskName != '设备申请'">
  33. <uni-tag type="primary" text="非项目设备申请"></uni-tag>
  34. </view>
  35. </uni-forms-item>
  36. <!-- 设备选择器 -->
  37. <device-picker :visible.sync="openDevice" :selected.sync="selectDevice" :multiple="!isReplaceMode"
  38. @confirm="handleDeviceConfirm"></device-picker>
  39. <!-- 设备选择 -->
  40. <uni-forms-item label="申请设备" required class="form-item" name="devices"
  41. v-if="taskName != '安排设备' && taskName != '归还确认'">
  42. <uv-button type="primary" @click="openDevice = true" v-if="taskName == '设备申请'">+ 选择设备</uv-button>
  43. <view class="device-cards" v-if="deviceList.length > 0">
  44. <view class="device-card" v-for="(item, index) in deviceList" :key="index">
  45. <view class="card-header">
  46. <text class="card-title">{{ index + 1 }}. 出厂编号:{{ item.code }}</text>
  47. </view>
  48. <view class="card-content">
  49. <view class="card-row">
  50. <view class="card-item">
  51. <text class="label">设备名称:</text>
  52. <text class="value">{{ item.name }}</text>
  53. </view>
  54. </view>
  55. <view class="card-row">
  56. <view class="card-item">
  57. <text class="label">设备品牌:</text>
  58. <text class="value">{{ item.brand }}</text>
  59. </view>
  60. <view class="card-item">
  61. <text class="label">存放地址:</text>
  62. <text class="value">{{ item.place }}</text>
  63. </view>
  64. </view>
  65. <view class="card-row">
  66. <view class="card-item">
  67. <text class="label">规格型号:</text>
  68. <text class="value">{{ item.series }}</text>
  69. </view>
  70. </view>
  71. </view>
  72. </view>
  73. </view>
  74. </uni-forms-item>
  75. <!-- 申领事由 -->
  76. <uni-forms-item label="申领事由" required class="form-item" name="applyReason">
  77. <uv-textarea v-model="form.applyReason" placeholder="请输入申领事由" :disabled="taskName != '设备申请'"></uv-textarea>
  78. </uni-forms-item>
  79. <!-- 日期选择 -->
  80. <view class="date-range">
  81. <uni-forms-item label="使用日期" required class="form-item" name="dateRange">
  82. <uni-datetime-picker v-model="form.dateRange" type="daterange" rangeSeparator="至" :clearIcon="false"
  83. v-if="taskName == '设备申请'" @change="handleDateRangeChange" />
  84. <view class="date-display" v-else>
  85. <uni-icons type="calendar" size="16"></uni-icons>
  86. <text class="date-text">{{ form.beginDate }}</text>
  87. <text class="date-separator">至</text>
  88. <text class="date-text">{{ form.endDate }}</text>
  89. </view>
  90. </uni-forms-item>
  91. <uni-forms-item label="共计" class="form-item">
  92. <text>{{ form.days + '天' }}</text>
  93. </uni-forms-item>
  94. </view>
  95. <!-- 安排设备意见 -->
  96. <uni-forms-item label="拟发放设备" required class="form-item" v-if="taskName != '设备申请' && taskName != '归还确认'">
  97. <view class="device-cards" v-if="modifyDeviceList.length > 0">
  98. <view class="device-card" v-for="(item, index) in modifyDeviceList" :key="index">
  99. <view class="card-header">
  100. <text class="card-title">{{ index + 1 }}. 出厂编号:{{ item.code }}</text>
  101. </view>
  102. <view class="card-content">
  103. <view class="card-row">
  104. <view class="card-item">
  105. <text class="label">设备名称:</text>
  106. <text class="value">{{ item.name }}</text>
  107. </view>
  108. </view>
  109. <view class="card-row">
  110. <view class="card-item">
  111. <text class="label">设备品牌:</text>
  112. <text class="value">{{ item.brand }}</text>
  113. </view>
  114. <view class="card-item">
  115. <text class="label">存放地址:</text>
  116. <text class="value">{{ item.place }}</text>
  117. </view>
  118. </view>
  119. <view class="card-row">
  120. <view class="card-item">
  121. <text class="label">规格型号:</text>
  122. <text class="value">{{ item.series }}</text>
  123. </view>
  124. </view>
  125. </view>
  126. <view class="card-actions" v-if="taskName == '安排设备'">
  127. <uv-button type="primary" size="mini" @click="replaceRowData(item, index)">重新选择</uv-button>
  128. <uv-button type="error" size="mini" @click="deleteRowData(item, index)">删除</uv-button>
  129. </view>
  130. </view>
  131. </view>
  132. <uv-button type="primary" @click="addRowdata()" v-if="taskName == '安排设备'">新增设备</uv-button>
  133. </uni-forms-item>
  134. <!-- 安排设备意见 -->
  135. <uni-forms-item label="安排设备意见" required class="form-item" name="dispatchComment" v-if="taskName != '设备申请'">
  136. <uv-textarea v-model="form.dispatchComment" placeholder="请输入安排设备意见"
  137. :disabled="taskName != '安排设备'"></uv-textarea>
  138. <auditor :name="form.dispatcher ? form.dispatchUser.nickName : ''" :time="form.dispatchTime"></auditor>
  139. </uni-forms-item>
  140. <!-- 分管审核意见 -->
  141. <uni-forms-item label="分管审核意见" required name="managerComment" class="form-item"
  142. v-if="taskName != '设备申请' && taskName != '安排设备'">
  143. <uv-textarea v-model="form.managerComment" placeholder="请输入分管审核意见" :disabled="taskName != '分管审核'"></uv-textarea>
  144. <auditor :name="form.managerUser ? form.managerUser.nickName : ''" :time="form.managerTime"></auditor>
  145. </uni-forms-item>
  146. <!-- 归还确认 -->
  147. <uni-forms-item label="已归还设备" required class="form-item" v-if="taskName == '' || taskName == '归还确认'">
  148. <text style="color: #3c9cff;" v-if="taskName == '归还确认'">Tips:请点击卡片,切换归还状态</text>
  149. <view class="device-cards" v-if="returnDevicesList.length > 0">
  150. <view class="device-card" v-for="(item, index) in returnDevicesList" :key="index"
  151. :class="{ 'selected': isDeviceSelected(item.deviceId) }" @click="toggleDeviceSelection(item)">
  152. <view class="card-header">
  153. <text class="card-title">{{ index + 1 }}. 出厂编号:{{ item.code }}</text>
  154. <view class="return-tag" v-if="isDeviceSelected(item.deviceId)">
  155. <uni-tag type="success" text="已归还" size="small"></uni-tag>
  156. </view>
  157. </view>
  158. <view class="card-content">
  159. <view class="card-row">
  160. <view class="card-item">
  161. <text class="label">设备名称:</text>
  162. <text class="value">{{ item.name }}</text>
  163. </view>
  164. </view>
  165. <view class="card-row">
  166. <view class="card-item">
  167. <text class="label">设备品牌:</text>
  168. <text class="value">{{ item.brand }}</text>
  169. </view>
  170. <view class="card-item">
  171. <text class="label">存放地址:</text>
  172. <text class="value">{{ item.place }}</text>
  173. </view>
  174. </view>
  175. <view class="card-row">
  176. <view class="card-item">
  177. <text class="label">规格型号:</text>
  178. <text class="value">{{ item.series }}</text>
  179. </view>
  180. </view>
  181. </view>
  182. </view>
  183. </view>
  184. </uni-forms-item>
  185. <!-- 需维修设备 -->
  186. <uni-forms-item label="需维修设备" class="form-item" v-if="taskName == '' || taskName == '归还确认'">
  187. <uv-button type="primary" @click="openRepairDevice = true" v-if="taskName == '归还确认'">+ 选择需维修设备</uv-button>
  188. <repair-device-picker :visible.sync="openRepairDevice" :deviceList="modifyDeviceList"
  189. :selectedDevices.sync="form.repairDevices"></repair-device-picker>
  190. <view class="device-cards" v-if="repairDevicesList.length > 0">
  191. <view class="device-card repair-card" v-for="(item, index) in repairDevicesList" :key="index">
  192. <view class="card-header">
  193. <text class="card-title">{{ index + 1 }}. 出厂编号:{{ item.code }}</text>
  194. <view class="repair-tag">
  195. <uni-tag type="error" text="需维修" size="small"></uni-tag>
  196. </view>
  197. </view>
  198. <view class="card-content">
  199. <view class="card-row">
  200. <view class="card-item">
  201. <text class="label">设备名称:</text>
  202. <text class="value">{{ item.name }}</text>
  203. </view>
  204. </view>
  205. <view class="card-row">
  206. <view class="card-item">
  207. <text class="label">设备品牌:</text>
  208. <text class="value">{{ item.brand }}</text>
  209. </view>
  210. <view class="card-item">
  211. <text class="label">存放地址:</text>
  212. <text class="value">{{ item.place }}</text>
  213. </view>
  214. </view>
  215. <view class="card-row">
  216. <view class="card-item">
  217. <text class="label">规格型号:</text>
  218. <text class="value">{{ item.series }}</text>
  219. </view>
  220. </view>
  221. </view>
  222. </view>
  223. </view>
  224. <view v-if="repairDevicesList.length == 0 && taskName != '归还确认'" style="margin-top: 10rpx;">
  225. <uni-tag type="success" text="没有需维修的设备" size="small"></uni-tag>
  226. </view>
  227. </uni-forms-item>
  228. <!-- 备注 -->
  229. <uni-forms-item label="备注" class="form-item" v-if="taskName == '' || taskName == '归还确认'">
  230. <uv-textarea v-model="form.remark" placeholder="请输入备注" :disabled="taskName != '归还确认'"></uv-textarea>
  231. </uni-forms-item>
  232. <!-- 归还日期 -->
  233. <uni-forms-item label="归还日期" required name="returnDate" class="form-item"
  234. v-if="taskName == '' || taskName == '归还确认'">
  235. <uni-datetime-picker v-model="form.returnDate" type="date" :disabled="taskName != '归还确认'" />
  236. </uni-forms-item>
  237. <!-- 操作按钮 -->
  238. <view class="form-actions" v-if="taskName">
  239. <uv-button type="primary" @click="submit" v-if="taskName == '设备申请'">提交申请</uv-button>
  240. <template v-else>
  241. <uv-button style="margin-bottom: 5px;" type="warning" @click="saves">保存</uv-button>
  242. <uv-button type="primary" @click="completeApply">完成审批</uv-button>
  243. </template>
  244. </view>
  245. </uni-forms>
  246. </view>
  247. </template>
  248. <script>
  249. import { parseTime } from "@/utils/common.js"
  250. import { getDeviceApproval, submitDeviceApproval, modifyDeviceApproval } from '@/api/oa/device/deviceApproval'
  251. import { complete, getNextFlowNode } from "@/api/flowable/todo";
  252. import { getProject } from "@/api/oa/project/project";
  253. import { getDevice } from "@/api/oa/device/device";
  254. import { getUserByRole } from "@/api/system/role";
  255. import { getUsersManageLeader } from '@/api/system/post.js'
  256. import { sendQyMessage } from "@/api/qywx/index";
  257. import { listUser, getUser } from "@/api/system/user";
  258. import FlowNote from '@/pages/components/flowNote.vue';
  259. import ProjectPicker from '@/pages/components/ProjectPicker.vue';
  260. import ProjectInfo from '@/pages/components/ProjectInfo.vue';
  261. import DevicePicker from "@/pages/components/DevicePicker.vue";
  262. import Auditor from "@/pages/components/auditor.vue";
  263. import RepairDevicePicker from "@/pages/components/RepairDevicePicker.vue";
  264. export default {
  265. components: {
  266. FlowNote,
  267. ProjectPicker,
  268. ProjectInfo,
  269. DevicePicker,
  270. Auditor,
  271. RepairDevicePicker
  272. },
  273. props: {
  274. taskForm: Object,
  275. taskName: String,
  276. startUserName: String,
  277. },
  278. created() {
  279. this.applierUserName = this.startUserName;
  280. this.initForm();
  281. this.getUserList();
  282. },
  283. data() {
  284. return {
  285. form: {
  286. userList: [],
  287. user: {
  288. nickName: ''
  289. },
  290. dept: {
  291. deptName: ''
  292. },
  293. projectId: '',
  294. applyDate: '',
  295. applyReason: '',
  296. beginDate: '',
  297. endDate: '',
  298. dateRange: [],
  299. days: 0,
  300. dispatchComment: '',
  301. managerComment: '',
  302. devices: [],
  303. modifyDevices: [],
  304. returnDevices: [],
  305. repairDevices: [],
  306. remark: '',
  307. returnDate: ''
  308. },
  309. rules: {
  310. // projectId: {
  311. // rules: [{ required: true, errorMessage: '请选择项目' }]
  312. // },
  313. devices: {
  314. rules: [{ required: true, errorMessage: '请选择设备' }]
  315. },
  316. applyReason: {
  317. rules: [{ required: true, errorMessage: '请输入申领事由' }]
  318. },
  319. dateRange: {
  320. rules: [{
  321. required: this.taskName === '设备申请',
  322. errorMessage: '请选择使用日期',
  323. validateFunction: (rule, value, data, callback) => {
  324. if (!value || value.length !== 2 || !value[0] || !value[1]) {
  325. callback('请选择使用日期');
  326. } else {
  327. callback();
  328. }
  329. }
  330. }]
  331. },
  332. dispatchComment: {
  333. rules: [{
  334. required: true,
  335. errorMessage: '请输入安排设备意见',
  336. validateFunction: (rule, value, data, callback) => {
  337. if (this.taskName === '安排设备' && !value) {
  338. callback('请输入安排设备意见');
  339. } else {
  340. callback();
  341. }
  342. }
  343. }]
  344. },
  345. managerComment: {
  346. rules: [{
  347. required: true,
  348. errorMessage: '请输入分管审核意见',
  349. validateFunction: (rule, value, data, callback) => {
  350. if (this.taskName === '分管审核' && !value) {
  351. callback('请输入分管审核意见');
  352. } else {
  353. callback();
  354. }
  355. }
  356. }]
  357. },
  358. returnDate: {
  359. rules: [{
  360. required: true,
  361. errorMessage: '请选择归还日期',
  362. validateFunction: (rule, value, data, callback) => {
  363. if (this.taskName === '归还确认' && !value) {
  364. callback('请选择归还日期');
  365. } else {
  366. callback();
  367. }
  368. }
  369. }]
  370. }
  371. },
  372. applierUserName: '',
  373. openProject: false,
  374. selectedProject: null,
  375. projectObj: {},
  376. openDevice: false,
  377. selectDevice: [],
  378. deviceList: [],
  379. modifyDeviceList: [],
  380. returnDevicesList: [],
  381. formTotal: 0,
  382. currentIndex: -1,
  383. isReplaceMode: false,
  384. openRepairDevice: false,
  385. repairDevicesList: []
  386. };
  387. },
  388. watch: {
  389. 'form.repairDevices': {
  390. handler(newVal) {
  391. this.updateRepairDevicesList();
  392. },
  393. immediate: true
  394. }
  395. },
  396. methods: {
  397. async initForm() {
  398. try {
  399. const res = await getDeviceApproval(this.taskForm.formId);
  400. if (res.data) {
  401. this.formTotal = 1;
  402. this.form = res.data;
  403. this.applierUserName = res.data.applierUser.nickName;
  404. if (res.data.projectId != '0') {
  405. const project = await getProject(res.data.projectId);
  406. this.projectObj = project.data;
  407. }
  408. // 初始化申请设备
  409. if (res.data.devices) {
  410. const deviceIds = res.data.devices.split(',').map(id => parseInt(id));
  411. this.form.devices = res.data.devices.split(',').map(id => parseInt(id));
  412. this.deviceList = [];
  413. this.selectDevice = [];
  414. for (const id of deviceIds) {
  415. const response = await getDevice(id);
  416. if (response.data) {
  417. this.deviceList.push(response.data);
  418. this.selectDevice.push(response.data);
  419. }
  420. }
  421. } else {
  422. this.deviceList = [];
  423. }
  424. // 初始化拟发放设备列表
  425. if (res.data.modifyDevices) {
  426. const modifyDeviceIds = typeof res.data.modifyDevices === 'string'
  427. ? res.data.modifyDevices.split(',').map(id => parseInt(id))
  428. : Array.isArray(res.data.modifyDevices)
  429. ? res.data.modifyDevices.map(id => parseInt(id))
  430. : [];
  431. this.form.modifyDevices = res.data.modifyDevices.split(',').map(id => parseInt(id));
  432. this.modifyDeviceList = [];
  433. for (const id of modifyDeviceIds) {
  434. const response = await getDevice(id);
  435. if (response.data) {
  436. this.modifyDeviceList.push(response.data);
  437. }
  438. }
  439. } else if (this.taskName === '安排设备') {
  440. this.modifyDeviceList = [...this.deviceList];
  441. } else {
  442. this.modifyDeviceList = [];
  443. }
  444. // 初始化归还设备列表
  445. if (res.data.returnDevices) {
  446. const returnDeviceIds = typeof res.data.returnDevices === 'string'
  447. ? res.data.returnDevices.split(',').map(id => parseInt(id))
  448. : Array.isArray(res.data.returnDevices)
  449. ? res.data.returnDevices.map(id => parseInt(id))
  450. : [];
  451. this.form.returnDevices = returnDeviceIds;
  452. // 获取所有拟发放的设备
  453. const modifyDeviceIds = typeof res.data.modifyDevices === 'string'
  454. ? res.data.modifyDevices.split(',').map(id => parseInt(id))
  455. : Array.isArray(res.data.modifyDevices)
  456. ? res.data.modifyDevices.map(id => parseInt(id))
  457. : [];
  458. this.returnDevicesList = [];
  459. for (const id of modifyDeviceIds) {
  460. const response = await getDevice(id);
  461. if (response.data) {
  462. this.returnDevicesList.push(response.data);
  463. }
  464. }
  465. } else if (this.taskName === '归还确认') {
  466. // 在归还确认节点,使用拟发放的设备列表
  467. this.returnDevicesList = [...this.modifyDeviceList];
  468. this.form.returnDevices = []; // 初始化空数组
  469. } else {
  470. this.returnDevicesList = [];
  471. this.form.returnDevices = []; // 初始化空数组
  472. }
  473. // 初始化维修设备列表
  474. if (res.data.repairDevices) {
  475. const repairDeviceIds = typeof res.data.repairDevices === 'string'
  476. ? res.data.repairDevices.split(',').map(id => parseInt(id))
  477. : Array.isArray(res.data.repairDevices)
  478. ? res.data.repairDevices.map(id => parseInt(id))
  479. : [];
  480. this.form.repairDevices = repairDeviceIds;
  481. this.updateRepairDevicesList();
  482. } else if (this.taskName === '归还确认') {
  483. this.form.repairDevices = [];
  484. this.repairDevicesList = [];
  485. }
  486. if (this.form.beginDate && this.form.endDate) {
  487. let dateRange = [this.form.beginDate, this.form.endDate];
  488. this.$set(this.form, 'dateRange', dateRange);
  489. }
  490. } else {
  491. this.form.applier = this.$store.getters.userId;
  492. this.form.applyDate = parseTime(new Date(), "{y}-{m}-{d}");
  493. let name = this.applierUserName.split('-');
  494. this.form.user.nickName = name[0];
  495. this.form.dept.deptName = name[1];
  496. this.formTotal = 0;
  497. this.form.returnDevices = []; // 初始化空数组
  498. this.form.repairDevices = []; // 初始化空数组
  499. }
  500. } catch (error) {
  501. console.error('初始化表单失败:', error);
  502. uni.showToast({
  503. title: '初始化表单失败',
  504. icon: 'error'
  505. });
  506. }
  507. },
  508. // 获取用户列表
  509. getUserList() {
  510. listUser({
  511. pageNum: 1,
  512. pageSize: 9999
  513. }).then(res => {
  514. if (res.code == 200) {
  515. this.userList = res.rows
  516. }
  517. })
  518. },
  519. handleConfirm(project) {
  520. this.selectedProject = project;
  521. this.projectObj = project;
  522. this.form.projectId = project.projectId;
  523. },
  524. handleDeviceConfirm(devices) {
  525. if (this.taskName === '安排设备') {
  526. if (this.currentIndex >= 0) {
  527. // 替换指定位置的设备,确保只使用第一个选中的设备
  528. const selectedDevice = Array.isArray(devices) ? devices[0] : devices;
  529. this.modifyDeviceList.splice(this.currentIndex, 1, selectedDevice);
  530. } else {
  531. // 新增设备
  532. this.modifyDeviceList.push(...devices);
  533. }
  534. this.isReplaceMode = false;
  535. } else {
  536. this.deviceList = Array.isArray(devices) ? devices : [devices];
  537. this.form.devices = this.deviceList.map(item => Number(item.deviceId));
  538. }
  539. },
  540. handleDateRangeChange(e) {
  541. if (Array.isArray(e) && e.length === 2) {
  542. const [start, end] = e;
  543. this.form.beginDate = start;
  544. this.form.endDate = end;
  545. this.form.dateRange = [start, end];
  546. this.calculateDay();
  547. }
  548. },
  549. calculateDay() {
  550. if (this.form.beginDate && this.form.endDate) {
  551. const begin = new Date(this.form.beginDate);
  552. const end = new Date(this.form.endDate);
  553. if (!isNaN(begin.getTime()) && !isNaN(end.getTime())) {
  554. this.form.days = Math.ceil((end - begin) / (1000 * 60 * 60 * 24)) + 1;
  555. }
  556. }
  557. },
  558. replaceRowData(row, index) {
  559. this.openDevice = true;
  560. this.currentIndex = index;
  561. this.isReplaceMode = true;
  562. // 在安排设备节点时,设置当前选中的设备
  563. if (this.taskName === '安排设备') {
  564. this.selectDevice = [row];
  565. }
  566. },
  567. deleteRowData(row, index) {
  568. uni.showModal({
  569. title: '确认删除',
  570. content: '确定要删除该设备吗?',
  571. success: (res) => {
  572. if (res.confirm) {
  573. this.modifyDeviceList.splice(index, 1);
  574. }
  575. }
  576. });
  577. },
  578. addRowdata() {
  579. this.openDevice = true;
  580. this.currentIndex = -1;
  581. this.isReplaceMode = false;
  582. // 在安排设备节点时,清空已选设备
  583. if (this.taskName === '安排设备') {
  584. this.selectDevice = [];
  585. }
  586. },
  587. async submit() {
  588. this.$refs.form.validate().then(async () => {
  589. this.$modal.confirm('是否提交设备申请?').then(async () => {
  590. let submitData = {
  591. ...this.form,
  592. ...(this.form.formId ? {} : { formId: this.taskForm.formId }),
  593. ...(this.form.deviceApplyId ? {} : { deviceApplyId: this.taskForm.formId })
  594. };
  595. let jsonForm = JSON.stringify(submitData);
  596. if (!this.form.deviceApplyId) {
  597. submitDeviceApproval(jsonForm).then(async res => {
  598. // 获取下一个流程节点
  599. await this.getNextFlowNodeApproval();
  600. // 发送企业微信消息
  601. await this.sendQyMessage();
  602. uni.showToast({
  603. title: '提交成功',
  604. icon: 'success'
  605. });
  606. setTimeout(() => {
  607. uni.switchTab({
  608. url: '/pages/message/index'
  609. })
  610. }, 500);
  611. });
  612. } else {
  613. modifyDeviceApproval(jsonForm).then(async res => {
  614. // 获取下一个流程节点
  615. await this.getNextFlowNodeApproval();
  616. // 发送企业微信消息
  617. await this.sendQyMessage();
  618. uni.showToast({
  619. title: '提交成功',
  620. icon: 'success'
  621. });
  622. setTimeout(() => {
  623. uni.switchTab({
  624. url: '/pages/message/index'
  625. })
  626. }, 500);
  627. })
  628. }
  629. })
  630. });
  631. },
  632. saves() {
  633. try {
  634. this.$refs.form.validate().then(() => {
  635. let submitData = {
  636. ...this.form,
  637. ...(this.form.formId ? {} : { formId: this.taskForm.formId }),
  638. ...(this.form.deviceApplyId ? {} : { deviceApplyId: this.taskForm.formId })
  639. };
  640. // 在安排设备节点时,添加拟发放设备列表
  641. if (this.taskName === '安排设备') {
  642. submitData.modifyDevices = this.modifyDeviceList.map(item => item.deviceId);
  643. }
  644. let jsonForm = JSON.stringify(submitData);
  645. modifyDeviceApproval(jsonForm).then(res => {
  646. if (res.code === 200) {
  647. uni.showToast({
  648. title: '保存成功',
  649. icon: 'success'
  650. });
  651. } else {
  652. uni.showToast({
  653. title: res.msg || '保存失败',
  654. icon: 'error'
  655. });
  656. }
  657. })
  658. })
  659. } catch (error) {
  660. console.error('保存方法错误:', error);
  661. uni.showToast({
  662. title: error.message || '保存失败',
  663. icon: 'error'
  664. });
  665. }
  666. },
  667. async completeApply() {
  668. this.$refs.form.validate().then(async () => {
  669. // 在归还确认节点时,检查所有设备是否都已归还
  670. if (this.taskName === '归还确认') {
  671. const allDevices = this.modifyDeviceList.map(item => item.deviceId);
  672. const returnedDevices = this.form.returnDevices || [];
  673. const unreturnedDevices = allDevices.filter(id => !returnedDevices.includes(id));
  674. if (unreturnedDevices.length > 0) {
  675. uni.showToast({
  676. title: '请确认所有设备都已归还',
  677. icon: 'none'
  678. });
  679. return;
  680. }
  681. }
  682. uni.showModal({
  683. title: '提示',
  684. content: '确定提交审批吗?',
  685. success: async (res) => {
  686. if (res.confirm) {
  687. let submitData = {
  688. ...this.form,
  689. ...(this.form.formId ? {} : { formId: this.taskForm.formId }),
  690. ...(this.form.deviceApplyId ? {} : { deviceApplyId: this.taskForm.formId })
  691. };
  692. // 在安排设备节点时,添加拟发放设备列表
  693. if (this.taskName === '安排设备') {
  694. submitData.modifyDevices = this.modifyDeviceList.map(item => item.deviceId);
  695. }
  696. let jsonForm = JSON.stringify(submitData);
  697. modifyDeviceApproval(jsonForm).then(async res => {
  698. // 获取下一个流程节点
  699. await getNextFlowNode({ taskId: this.taskForm.taskId });
  700. await this.getNextFlowNodeApproval();
  701. uni.showToast({
  702. title: '提交成功',
  703. icon: 'success'
  704. });
  705. setTimeout(() => {
  706. uni.switchTab({
  707. url: '/pages/message/index'
  708. });
  709. }, 500);
  710. });
  711. }
  712. }
  713. });
  714. });
  715. },
  716. // 获取下一个审批人
  717. getNextFlowNodeApproval() {
  718. return new Promise((resolve, reject) => {
  719. const handleComplete = (response) => {
  720. this.$modal.msgSuccess(response.msg);
  721. resolve();
  722. };
  723. const setApprovalAndComplete = (result) => {
  724. this.$set(this.taskForm.variables, "approval", result.data[0]);
  725. complete(this.taskForm).then(handleComplete).catch(reject);
  726. };
  727. switch (this.taskName) {
  728. case '设备申请':
  729. case '分管审核':
  730. getUserByRole({ roleId: 4 }).then(setApprovalAndComplete).catch(reject);
  731. break;
  732. case '安排设备':
  733. getUsersManageLeader({ userId: this.form.applier }).then(res => {
  734. const userIds = res.data.map(user => user.userId);
  735. this.$set(this.taskForm.variables, "approvalList", userIds);
  736. complete(this.taskForm).then(handleComplete).catch(reject);
  737. }).catch(reject);
  738. break;
  739. case '归还确认':
  740. this.$modal.confirm('最后一个节点,提交将结束流程,是否提交?')
  741. .then(() => complete(this.taskForm).then(handleComplete).catch(reject))
  742. .catch(reject);
  743. break;
  744. }
  745. });
  746. },
  747. isDeviceSelected(deviceId) {
  748. return this.form.returnDevices && this.form.returnDevices.includes(deviceId);
  749. },
  750. toggleDeviceSelection(device) {
  751. if (this.taskName !== '归还确认') return;
  752. // 确保 returnDevices 是数组
  753. if (!Array.isArray(this.form.returnDevices)) {
  754. this.form.returnDevices = [];
  755. }
  756. const index = this.form.returnDevices.indexOf(device.deviceId);
  757. if (index === -1) {
  758. // 添加设备到已归还列表
  759. this.form.returnDevices.push(device.deviceId);
  760. } else {
  761. // 从已归还列表中移除设备
  762. this.form.returnDevices.splice(index, 1);
  763. }
  764. },
  765. updateRepairDevicesList() {
  766. // 如果 repairDevices 是字符串,转换为数组
  767. if (typeof this.form.repairDevices === 'string') {
  768. this.form.repairDevices = this.form.repairDevices.split(',').map(id => parseInt(id));
  769. } else if (!Array.isArray(this.form.repairDevices)) {
  770. this.form.repairDevices = [];
  771. }
  772. this.repairDevicesList = this.modifyDeviceList.filter(device =>
  773. this.form.repairDevices.includes(device.deviceId)
  774. );
  775. },
  776. // 发送企业微信消息
  777. async sendQyMessage() {
  778. try {
  779. let userIds = [];
  780. let userString = [];
  781. let message = '';
  782. let formData = new FormData();
  783. // 获取下一个审批人
  784. if (this.taskName == '设备申请') {
  785. let result = await getUserByRole({ roleId: 4 });
  786. if (result.data && result.data.length > 0) {
  787. userIds.push(result.data[0]);
  788. }
  789. } else if (this.taskName == '安排设备') {
  790. let res = await getUsersManageLeader({ userId: this.form.applier });
  791. if (res.data) {
  792. res.data.forEach(user => {
  793. userIds.push(user.userId);
  794. });
  795. }
  796. }
  797. for (let u of userIds) {
  798. let { data } = await getUser(u);
  799. if (data) {
  800. userString.push(data.pinyin);
  801. }
  802. }
  803. message = "您有一条新的设备申请: \n>" +
  804. "申请人:<font color='info'>" + this.getUserName(this.form.applier) + "</font> \n>" +
  805. "开始日期:" + this.form.beginDate + " \n>" +
  806. "结束日期:" + this.form.endDate + " \n>" +
  807. "申请事由:" + this.form.applyReason + " \n>" +
  808. "\n>" +
  809. "已办流程:<font color='comment'>" + this.taskName + "</font> \n>";
  810. formData.append('message', message);
  811. formData.append('userString', userString.join('|') + '|YuSiHan|WangRongHua')
  812. if (userIds.length > 0) {
  813. await sendQyMessage(formData);
  814. }
  815. } catch (error) {
  816. console.error('发送企业微信消息失败:', error);
  817. }
  818. },
  819. // 获取用户名称
  820. getUserName(userId) {
  821. if (!userId || !this.userList) return '';
  822. let user = this.userList.find(u => u.userId == userId);
  823. return user ? user.nickName : '';
  824. },
  825. }
  826. }
  827. </script>
  828. <style lang="scss" scoped>
  829. .form-container {
  830. padding: 32rpx;
  831. }
  832. .form-title {
  833. text-align: center;
  834. margin-bottom: 32rpx;
  835. .title-text {
  836. font-size: 36rpx;
  837. font-weight: bold;
  838. }
  839. .title-line {
  840. height: 2rpx;
  841. background: #eee;
  842. margin-top: 16rpx;
  843. }
  844. }
  845. .date-range {
  846. // display: flex;
  847. flex-wrap: wrap;
  848. gap: 32rpx;
  849. }
  850. .date-text {
  851. margin: 0 10px;
  852. font-weight: bold;
  853. }
  854. .form-actions {
  855. justify-content: center;
  856. gap: 32rpx;
  857. margin-top: 32rpx;
  858. }
  859. ::v-deep .uni-forms-item__label {
  860. font-weight: bold;
  861. }
  862. .device-cards {
  863. margin-top: 20rpx;
  864. }
  865. .device-card {
  866. background: #fff;
  867. border-radius: 12rpx;
  868. margin-bottom: 20rpx;
  869. box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1);
  870. overflow: hidden;
  871. transition: all 0.3s ease;
  872. cursor: pointer;
  873. &.selected {
  874. border: 2rpx solid #67c23a;
  875. background-color: rgba(103, 194, 58, 0.05);
  876. }
  877. }
  878. .card-header {
  879. padding: 16rpx 20rpx;
  880. background: #f5f7fa;
  881. border-bottom: 1rpx solid #eee;
  882. display: flex;
  883. justify-content: space-between;
  884. align-items: center;
  885. }
  886. .return-tag {
  887. margin-left: 10rpx;
  888. }
  889. .card-title {
  890. font-size: 28rpx;
  891. font-weight: bold;
  892. color: #333;
  893. display: block;
  894. overflow: hidden;
  895. text-overflow: ellipsis;
  896. white-space: nowrap;
  897. }
  898. .card-content {
  899. padding: 16rpx 20rpx;
  900. }
  901. .card-row {
  902. display: flex;
  903. margin-bottom: 12rpx;
  904. &:last-child {
  905. margin-bottom: 0;
  906. }
  907. }
  908. .card-item {
  909. flex: 1;
  910. display: flex;
  911. align-items: center;
  912. font-size: 26rpx;
  913. line-height: 1.4;
  914. padding: 0 10rpx;
  915. min-width: 0; // 防止内容溢出
  916. .label {
  917. color: #666;
  918. flex-shrink: 0;
  919. margin-right: 8rpx;
  920. }
  921. .value {
  922. color: #333;
  923. flex: 1;
  924. overflow: hidden;
  925. text-overflow: ellipsis;
  926. white-space: nowrap;
  927. }
  928. }
  929. .card-actions {
  930. padding: 16rpx 20rpx;
  931. display: flex;
  932. justify-content: flex-end;
  933. gap: 20rpx;
  934. border-top: 1rpx solid #eee;
  935. }
  936. .device-card {
  937. background: #fff;
  938. border-radius: 12rpx;
  939. margin-bottom: 20rpx;
  940. box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1);
  941. overflow: hidden;
  942. transition: all 0.3s ease;
  943. cursor: pointer;
  944. &.repair-card {
  945. border: 2rpx solid #f56c6c;
  946. background-color: rgba(245, 108, 108, 0.05);
  947. }
  948. }
  949. .card-header {
  950. padding: 16rpx 20rpx;
  951. background: #f5f7fa;
  952. border-bottom: 1rpx solid #eee;
  953. display: flex;
  954. justify-content: space-between;
  955. align-items: center;
  956. }
  957. .repair-tag {
  958. margin-left: 10rpx;
  959. }
  960. </style>