综合办公系统
Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

device.vue 34KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953
  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 FlowNote from '@/pages/components/flowNote.vue';
  257. import ProjectPicker from '@/pages/components/ProjectPicker.vue';
  258. import ProjectInfo from '@/pages/components/ProjectInfo.vue';
  259. import DevicePicker from "@/pages/components/DevicePicker.vue";
  260. import Auditor from "@/pages/components/auditor.vue";
  261. import RepairDevicePicker from "@/pages/components/RepairDevicePicker.vue";
  262. export default {
  263. components: {
  264. FlowNote,
  265. ProjectPicker,
  266. ProjectInfo,
  267. DevicePicker,
  268. Auditor,
  269. RepairDevicePicker
  270. },
  271. props: {
  272. taskForm: Object,
  273. taskName: String,
  274. startUserName: String,
  275. },
  276. created() {
  277. this.applierUserName = this.startUserName;
  278. this.initForm();
  279. },
  280. data() {
  281. return {
  282. form: {
  283. user: {
  284. nickName: ''
  285. },
  286. dept: {
  287. deptName: ''
  288. },
  289. projectId: '',
  290. applyDate: '',
  291. applyReason: '',
  292. beginDate: '',
  293. endDate: '',
  294. dateRange: [],
  295. days: 0,
  296. dispatchComment: '',
  297. managerComment: '',
  298. devices: [],
  299. modifyDevices: [],
  300. returnDevices: [],
  301. repairDevices: [],
  302. remark: '',
  303. returnDate: ''
  304. },
  305. rules: {
  306. // projectId: {
  307. // rules: [{ required: true, errorMessage: '请选择项目' }]
  308. // },
  309. devices: {
  310. rules: [{ required: true, errorMessage: '请选择设备' }]
  311. },
  312. applyReason: {
  313. rules: [{ required: true, errorMessage: '请输入申领事由' }]
  314. },
  315. dateRange: {
  316. rules: [{
  317. required: this.taskName === '设备申请',
  318. errorMessage: '请选择使用日期',
  319. validateFunction: (rule, value, data, callback) => {
  320. if (!value || value.length !== 2 || !value[0] || !value[1]) {
  321. callback('请选择使用日期');
  322. } else {
  323. callback();
  324. }
  325. }
  326. }]
  327. },
  328. dispatchComment: {
  329. rules: [{
  330. required: true,
  331. errorMessage: '请输入安排设备意见',
  332. validateFunction: (rule, value, data, callback) => {
  333. if (this.taskName === '安排设备' && !value) {
  334. callback('请输入安排设备意见');
  335. } else {
  336. callback();
  337. }
  338. }
  339. }]
  340. },
  341. managerComment: {
  342. rules: [{
  343. required: true,
  344. errorMessage: '请输入分管审核意见',
  345. validateFunction: (rule, value, data, callback) => {
  346. if (this.taskName === '分管审核' && !value) {
  347. callback('请输入分管审核意见');
  348. } else {
  349. callback();
  350. }
  351. }
  352. }]
  353. },
  354. returnDate: {
  355. rules: [{
  356. required: true,
  357. errorMessage: '请选择归还日期',
  358. validateFunction: (rule, value, data, callback) => {
  359. if (this.taskName === '归还确认' && !value) {
  360. callback('请选择归还日期');
  361. } else {
  362. callback();
  363. }
  364. }
  365. }]
  366. }
  367. },
  368. applierUserName: '',
  369. openProject: false,
  370. selectedProject: null,
  371. projectObj: {},
  372. openDevice: false,
  373. selectDevice: [],
  374. deviceList: [],
  375. modifyDeviceList: [],
  376. returnDevicesList: [],
  377. formTotal: 0,
  378. currentIndex: -1,
  379. isReplaceMode: false,
  380. openRepairDevice: false,
  381. repairDevicesList: []
  382. };
  383. },
  384. watch: {
  385. 'form.repairDevices': {
  386. handler(newVal) {
  387. this.updateRepairDevicesList();
  388. },
  389. immediate: true
  390. }
  391. },
  392. methods: {
  393. async initForm() {
  394. try {
  395. const res = await getDeviceApproval(this.taskForm.formId);
  396. if (res.data) {
  397. this.formTotal = 1;
  398. this.form = res.data;
  399. this.applierUserName = res.data.applierUser.nickName;
  400. if (res.data.projectId != '0') {
  401. const project = await getProject(res.data.projectId);
  402. this.projectObj = project.data;
  403. }
  404. // 初始化申请设备
  405. if (res.data.devices) {
  406. const deviceIds = res.data.devices.split(',').map(id => parseInt(id));
  407. this.form.devices = res.data.devices.split(',').map(id => parseInt(id));
  408. this.deviceList = [];
  409. this.selectDevice = [];
  410. for (const id of deviceIds) {
  411. const response = await getDevice(id);
  412. if (response.data) {
  413. this.deviceList.push(response.data);
  414. this.selectDevice.push(response.data);
  415. }
  416. }
  417. } else {
  418. this.deviceList = [];
  419. }
  420. // 初始化拟发放设备列表
  421. if (res.data.modifyDevices) {
  422. const modifyDeviceIds = typeof res.data.modifyDevices === 'string'
  423. ? res.data.modifyDevices.split(',').map(id => parseInt(id))
  424. : Array.isArray(res.data.modifyDevices)
  425. ? res.data.modifyDevices.map(id => parseInt(id))
  426. : [];
  427. this.form.modifyDevices = res.data.modifyDevices.split(',').map(id => parseInt(id));
  428. this.modifyDeviceList = [];
  429. for (const id of modifyDeviceIds) {
  430. const response = await getDevice(id);
  431. if (response.data) {
  432. this.modifyDeviceList.push(response.data);
  433. }
  434. }
  435. } else if (this.taskName === '安排设备') {
  436. this.modifyDeviceList = [...this.deviceList];
  437. } else {
  438. this.modifyDeviceList = [];
  439. }
  440. // 初始化归还设备列表
  441. if (res.data.returnDevices) {
  442. const returnDeviceIds = typeof res.data.returnDevices === 'string'
  443. ? res.data.returnDevices.split(',').map(id => parseInt(id))
  444. : Array.isArray(res.data.returnDevices)
  445. ? res.data.returnDevices.map(id => parseInt(id))
  446. : [];
  447. this.form.returnDevices = returnDeviceIds;
  448. // 获取所有拟发放的设备
  449. const modifyDeviceIds = typeof res.data.modifyDevices === 'string'
  450. ? res.data.modifyDevices.split(',').map(id => parseInt(id))
  451. : Array.isArray(res.data.modifyDevices)
  452. ? res.data.modifyDevices.map(id => parseInt(id))
  453. : [];
  454. this.returnDevicesList = [];
  455. for (const id of modifyDeviceIds) {
  456. const response = await getDevice(id);
  457. if (response.data) {
  458. this.returnDevicesList.push(response.data);
  459. }
  460. }
  461. } else if (this.taskName === '归还确认') {
  462. // 在归还确认节点,使用拟发放的设备列表
  463. this.returnDevicesList = [...this.modifyDeviceList];
  464. this.form.returnDevices = []; // 初始化空数组
  465. } else {
  466. this.returnDevicesList = [];
  467. this.form.returnDevices = []; // 初始化空数组
  468. }
  469. // 初始化维修设备列表
  470. if (res.data.repairDevices) {
  471. const repairDeviceIds = typeof res.data.repairDevices === 'string'
  472. ? res.data.repairDevices.split(',').map(id => parseInt(id))
  473. : Array.isArray(res.data.repairDevices)
  474. ? res.data.repairDevices.map(id => parseInt(id))
  475. : [];
  476. this.form.repairDevices = repairDeviceIds;
  477. this.updateRepairDevicesList();
  478. } else if (this.taskName === '归还确认') {
  479. this.form.repairDevices = [];
  480. this.repairDevicesList = [];
  481. }
  482. if (this.form.beginDate && this.form.endDate) {
  483. let dateRange = [this.form.beginDate, this.form.endDate];
  484. this.$set(this.form, 'dateRange', dateRange);
  485. }
  486. } else {
  487. this.form.applier = this.$store.getters.userId;
  488. this.form.applyDate = parseTime(new Date(), "{y}-{m}-{d}");
  489. let name = this.applierUserName.split('-');
  490. this.form.user.nickName = name[0];
  491. this.form.dept.deptName = name[1];
  492. this.formTotal = 0;
  493. this.form.returnDevices = []; // 初始化空数组
  494. this.form.repairDevices = []; // 初始化空数组
  495. }
  496. } catch (error) {
  497. console.error('初始化表单失败:', error);
  498. uni.showToast({
  499. title: '初始化表单失败',
  500. icon: 'error'
  501. });
  502. }
  503. },
  504. handleConfirm(project) {
  505. this.selectedProject = project;
  506. this.projectObj = project;
  507. this.form.projectId = project.projectId;
  508. },
  509. handleDeviceConfirm(devices) {
  510. if (this.taskName === '安排设备') {
  511. if (this.currentIndex >= 0) {
  512. // 替换指定位置的设备,确保只使用第一个选中的设备
  513. const selectedDevice = Array.isArray(devices) ? devices[0] : devices;
  514. this.modifyDeviceList.splice(this.currentIndex, 1, selectedDevice);
  515. } else {
  516. // 新增设备
  517. this.modifyDeviceList.push(...devices);
  518. }
  519. this.isReplaceMode = false;
  520. } else {
  521. this.deviceList = Array.isArray(devices) ? devices : [devices];
  522. this.form.devices = this.deviceList.map(item => Number(item.deviceId));
  523. }
  524. },
  525. handleDateRangeChange(e) {
  526. if (Array.isArray(e) && e.length === 2) {
  527. const [start, end] = e;
  528. this.form.beginDate = start;
  529. this.form.endDate = end;
  530. this.form.dateRange = [start, end];
  531. this.calculateDay();
  532. }
  533. },
  534. calculateDay() {
  535. if (this.form.beginDate && this.form.endDate) {
  536. const begin = new Date(this.form.beginDate);
  537. const end = new Date(this.form.endDate);
  538. if (!isNaN(begin.getTime()) && !isNaN(end.getTime())) {
  539. this.form.days = Math.ceil((end - begin) / (1000 * 60 * 60 * 24)) + 1;
  540. }
  541. }
  542. },
  543. replaceRowData(row, index) {
  544. this.openDevice = true;
  545. this.currentIndex = index;
  546. this.isReplaceMode = true;
  547. // 在安排设备节点时,设置当前选中的设备
  548. if (this.taskName === '安排设备') {
  549. this.selectDevice = [row];
  550. }
  551. },
  552. deleteRowData(row, index) {
  553. uni.showModal({
  554. title: '确认删除',
  555. content: '确定要删除该设备吗?',
  556. success: (res) => {
  557. if (res.confirm) {
  558. this.modifyDeviceList.splice(index, 1);
  559. }
  560. }
  561. });
  562. },
  563. addRowdata() {
  564. this.openDevice = true;
  565. this.currentIndex = -1;
  566. this.isReplaceMode = false;
  567. // 在安排设备节点时,清空已选设备
  568. if (this.taskName === '安排设备') {
  569. this.selectDevice = [];
  570. }
  571. },
  572. submit() {
  573. this.$refs.form.validate().then(() => {
  574. this.$modal.confirm('是否提交设备申请?').then(() => {
  575. let submitData = {
  576. ...this.form,
  577. ...(this.form.formId ? {} : { formId: this.taskForm.formId }),
  578. ...(this.form.deviceApplyId ? {} : { deviceApplyId: this.taskForm.formId })
  579. };
  580. let jsonForm = JSON.stringify(submitData);
  581. if (!this.form.deviceApplyId) {
  582. submitDeviceApproval(jsonForm).then(res => {
  583. // 获取下一个流程节点
  584. this.getNextFlowNodeApproval().then(() => {
  585. uni.showToast({
  586. title: '提交成功',
  587. icon: 'success'
  588. });
  589. setTimeout(() => {
  590. uni.switchTab({
  591. url: '/pages/message/index'
  592. })
  593. }, 500);
  594. })
  595. });
  596. } else {
  597. modifyDeviceApproval(jsonForm).then(res => {
  598. // 获取下一个流程节点
  599. this.getNextFlowNodeApproval().then(() => {
  600. uni.showToast({
  601. title: '提交成功',
  602. icon: 'success'
  603. });
  604. setTimeout(() => {
  605. uni.switchTab({
  606. url: '/pages/message/index'
  607. })
  608. }, 500);
  609. })
  610. })
  611. }
  612. })
  613. });
  614. },
  615. saves() {
  616. try {
  617. this.$refs.form.validate().then(() => {
  618. let submitData = {
  619. ...this.form,
  620. ...(this.form.formId ? {} : { formId: this.taskForm.formId }),
  621. ...(this.form.deviceApplyId ? {} : { deviceApplyId: this.taskForm.formId })
  622. };
  623. // 在安排设备节点时,添加拟发放设备列表
  624. if (this.taskName === '安排设备') {
  625. submitData.modifyDevices = this.modifyDeviceList.map(item => item.deviceId);
  626. }
  627. let jsonForm = JSON.stringify(submitData);
  628. modifyDeviceApproval(jsonForm).then(res => {
  629. if (res.code === 200) {
  630. uni.showToast({
  631. title: '保存成功',
  632. icon: 'success'
  633. });
  634. } else {
  635. uni.showToast({
  636. title: res.msg || '保存失败',
  637. icon: 'error'
  638. });
  639. }
  640. })
  641. })
  642. } catch (error) {
  643. console.error('保存方法错误:', error);
  644. uni.showToast({
  645. title: error.message || '保存失败',
  646. icon: 'error'
  647. });
  648. }
  649. },
  650. completeApply() {
  651. this.$refs.form.validate().then(() => {
  652. // 在归还确认节点时,检查所有设备是否都已归还
  653. if (this.taskName === '归还确认') {
  654. const allDevices = this.modifyDeviceList.map(item => item.deviceId);
  655. const returnedDevices = this.form.returnDevices || [];
  656. const unreturnedDevices = allDevices.filter(id => !returnedDevices.includes(id));
  657. if (unreturnedDevices.length > 0) {
  658. uni.showToast({
  659. title: '请确认所有设备都已归还',
  660. icon: 'none'
  661. });
  662. return;
  663. }
  664. }
  665. uni.showModal({
  666. title: '提示',
  667. content: '确定提交审批吗?',
  668. success: (res) => {
  669. if (res.confirm) {
  670. let submitData = {
  671. ...this.form,
  672. ...(this.form.formId ? {} : { formId: this.taskForm.formId }),
  673. ...(this.form.deviceApplyId ? {} : { deviceApplyId: this.taskForm.formId })
  674. };
  675. // 在安排设备节点时,添加拟发放设备列表
  676. if (this.taskName === '安排设备') {
  677. submitData.modifyDevices = this.modifyDeviceList.map(item => item.deviceId);
  678. }
  679. let jsonForm = JSON.stringify(submitData);
  680. modifyDeviceApproval(jsonForm).then(res => {
  681. // 获取下一个流程节点
  682. getNextFlowNode({ taskId: this.taskForm.taskId }).then(res => {
  683. this.getNextFlowNodeApproval().then(() => {
  684. uni.showToast({
  685. title: '提交成功',
  686. icon: 'success'
  687. });
  688. setTimeout(() => {
  689. uni.switchTab({
  690. url: '/pages/message/index'
  691. });
  692. }, 500);
  693. });
  694. });
  695. });
  696. }
  697. }
  698. });
  699. });
  700. },
  701. // 获取下一个审批人
  702. getNextFlowNodeApproval() {
  703. return new Promise((resolve, reject) => {
  704. const handleComplete = (response) => {
  705. this.$modal.msgSuccess(response.msg);
  706. resolve();
  707. };
  708. const setApprovalAndComplete = (result) => {
  709. this.$set(this.taskForm.variables, "approval", result.data[0]);
  710. complete(this.taskForm).then(handleComplete).catch(reject);
  711. };
  712. switch (this.taskName) {
  713. case '设备申请':
  714. case '分管审核':
  715. getUserByRole({ roleId: 4 }).then(setApprovalAndComplete).catch(reject);
  716. break;
  717. case '安排设备':
  718. getUsersManageLeader({ userId: this.form.applier }).then(res => {
  719. const userIds = res.data.map(user => user.userId);
  720. this.$set(this.taskForm.variables, "approvalList", userIds);
  721. complete(this.taskForm).then(handleComplete).catch(reject);
  722. }).catch(reject);
  723. break;
  724. case '归还确认':
  725. this.$modal.confirm('最后一个节点,提交将结束流程,是否提交?')
  726. .then(() => complete(this.taskForm).then(handleComplete).catch(reject))
  727. .catch(reject);
  728. break;
  729. }
  730. });
  731. },
  732. isDeviceSelected(deviceId) {
  733. return this.form.returnDevices && this.form.returnDevices.includes(deviceId);
  734. },
  735. toggleDeviceSelection(device) {
  736. if (this.taskName !== '归还确认') return;
  737. // 确保 returnDevices 是数组
  738. if (!Array.isArray(this.form.returnDevices)) {
  739. this.form.returnDevices = [];
  740. }
  741. const index = this.form.returnDevices.indexOf(device.deviceId);
  742. if (index === -1) {
  743. // 添加设备到已归还列表
  744. this.form.returnDevices.push(device.deviceId);
  745. } else {
  746. // 从已归还列表中移除设备
  747. this.form.returnDevices.splice(index, 1);
  748. }
  749. },
  750. updateRepairDevicesList() {
  751. // 如果 repairDevices 是字符串,转换为数组
  752. if (typeof this.form.repairDevices === 'string') {
  753. this.form.repairDevices = this.form.repairDevices.split(',').map(id => parseInt(id));
  754. } else if (!Array.isArray(this.form.repairDevices)) {
  755. this.form.repairDevices = [];
  756. }
  757. this.repairDevicesList = this.modifyDeviceList.filter(device =>
  758. this.form.repairDevices.includes(device.deviceId)
  759. );
  760. }
  761. }
  762. }
  763. </script>
  764. <style lang="scss" scoped>
  765. .form-container {
  766. padding: 32rpx;
  767. }
  768. .form-title {
  769. text-align: center;
  770. margin-bottom: 32rpx;
  771. .title-text {
  772. font-size: 36rpx;
  773. font-weight: bold;
  774. }
  775. .title-line {
  776. height: 2rpx;
  777. background: #eee;
  778. margin-top: 16rpx;
  779. }
  780. }
  781. .date-range {
  782. // display: flex;
  783. flex-wrap: wrap;
  784. gap: 32rpx;
  785. }
  786. .date-text {
  787. margin: 0 10px;
  788. font-weight: bold;
  789. }
  790. .form-actions {
  791. justify-content: center;
  792. gap: 32rpx;
  793. margin-top: 32rpx;
  794. }
  795. ::v-deep .uni-forms-item__label {
  796. font-weight: bold;
  797. }
  798. .device-cards {
  799. margin-top: 20rpx;
  800. }
  801. .device-card {
  802. background: #fff;
  803. border-radius: 12rpx;
  804. margin-bottom: 20rpx;
  805. box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1);
  806. overflow: hidden;
  807. transition: all 0.3s ease;
  808. cursor: pointer;
  809. &.selected {
  810. border: 2rpx solid #67c23a;
  811. background-color: rgba(103, 194, 58, 0.05);
  812. }
  813. }
  814. .card-header {
  815. padding: 16rpx 20rpx;
  816. background: #f5f7fa;
  817. border-bottom: 1rpx solid #eee;
  818. display: flex;
  819. justify-content: space-between;
  820. align-items: center;
  821. }
  822. .return-tag {
  823. margin-left: 10rpx;
  824. }
  825. .card-title {
  826. font-size: 28rpx;
  827. font-weight: bold;
  828. color: #333;
  829. display: block;
  830. overflow: hidden;
  831. text-overflow: ellipsis;
  832. white-space: nowrap;
  833. }
  834. .card-content {
  835. padding: 16rpx 20rpx;
  836. }
  837. .card-row {
  838. display: flex;
  839. margin-bottom: 12rpx;
  840. &:last-child {
  841. margin-bottom: 0;
  842. }
  843. }
  844. .card-item {
  845. flex: 1;
  846. display: flex;
  847. align-items: center;
  848. font-size: 26rpx;
  849. line-height: 1.4;
  850. padding: 0 10rpx;
  851. min-width: 0; // 防止内容溢出
  852. .label {
  853. color: #666;
  854. flex-shrink: 0;
  855. margin-right: 8rpx;
  856. }
  857. .value {
  858. color: #333;
  859. flex: 1;
  860. overflow: hidden;
  861. text-overflow: ellipsis;
  862. white-space: nowrap;
  863. }
  864. }
  865. .card-actions {
  866. padding: 16rpx 20rpx;
  867. display: flex;
  868. justify-content: flex-end;
  869. gap: 20rpx;
  870. border-top: 1rpx solid #eee;
  871. }
  872. .device-card {
  873. background: #fff;
  874. border-radius: 12rpx;
  875. margin-bottom: 20rpx;
  876. box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1);
  877. overflow: hidden;
  878. transition: all 0.3s ease;
  879. cursor: pointer;
  880. &.repair-card {
  881. border: 2rpx solid #f56c6c;
  882. background-color: rgba(245, 108, 108, 0.05);
  883. }
  884. }
  885. .card-header {
  886. padding: 16rpx 20rpx;
  887. background: #f5f7fa;
  888. border-bottom: 1rpx solid #eee;
  889. display: flex;
  890. justify-content: space-between;
  891. align-items: center;
  892. }
  893. .repair-tag {
  894. margin-left: 10rpx;
  895. }
  896. </style>