综合办公系统
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.

device.vue 36KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020
  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. formData.append('message', message);
  809. formData.append('userString', userString.join('|') + '|YuSiHan|WangRongHua')
  810. if (userIds.length > 0) {
  811. await sendQyMessage(formData);
  812. }
  813. } catch (error) {
  814. console.error('发送企业微信消息失败:', error);
  815. }
  816. },
  817. // 获取用户名称
  818. getUserName(userId) {
  819. if (!userId || !this.userList) return '';
  820. let user = this.userList.find(u => u.userId == userId);
  821. return user ? user.nickName : '';
  822. },
  823. }
  824. }
  825. </script>
  826. <style lang="scss" scoped>
  827. .form-container {
  828. padding: 32rpx;
  829. }
  830. .form-title {
  831. text-align: center;
  832. margin-bottom: 32rpx;
  833. .title-text {
  834. font-size: 36rpx;
  835. font-weight: bold;
  836. }
  837. .title-line {
  838. height: 2rpx;
  839. background: #eee;
  840. margin-top: 16rpx;
  841. }
  842. }
  843. .date-range {
  844. // display: flex;
  845. flex-wrap: wrap;
  846. gap: 32rpx;
  847. }
  848. .date-text {
  849. margin: 0 10px;
  850. font-weight: bold;
  851. }
  852. .form-actions {
  853. justify-content: center;
  854. gap: 32rpx;
  855. margin-top: 32rpx;
  856. }
  857. ::v-deep .uni-forms-item__label {
  858. font-weight: bold;
  859. }
  860. .device-cards {
  861. margin-top: 20rpx;
  862. }
  863. .device-card {
  864. background: #fff;
  865. border-radius: 12rpx;
  866. margin-bottom: 20rpx;
  867. box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1);
  868. overflow: hidden;
  869. transition: all 0.3s ease;
  870. cursor: pointer;
  871. &.selected {
  872. border: 2rpx solid #67c23a;
  873. background-color: rgba(103, 194, 58, 0.05);
  874. }
  875. }
  876. .card-header {
  877. padding: 16rpx 20rpx;
  878. background: #f5f7fa;
  879. border-bottom: 1rpx solid #eee;
  880. display: flex;
  881. justify-content: space-between;
  882. align-items: center;
  883. }
  884. .return-tag {
  885. margin-left: 10rpx;
  886. }
  887. .card-title {
  888. font-size: 28rpx;
  889. font-weight: bold;
  890. color: #333;
  891. display: block;
  892. overflow: hidden;
  893. text-overflow: ellipsis;
  894. white-space: nowrap;
  895. }
  896. .card-content {
  897. padding: 16rpx 20rpx;
  898. }
  899. .card-row {
  900. display: flex;
  901. margin-bottom: 12rpx;
  902. &:last-child {
  903. margin-bottom: 0;
  904. }
  905. }
  906. .card-item {
  907. flex: 1;
  908. display: flex;
  909. align-items: center;
  910. font-size: 26rpx;
  911. line-height: 1.4;
  912. padding: 0 10rpx;
  913. min-width: 0; // 防止内容溢出
  914. .label {
  915. color: #666;
  916. flex-shrink: 0;
  917. margin-right: 8rpx;
  918. }
  919. .value {
  920. color: #333;
  921. flex: 1;
  922. overflow: hidden;
  923. text-overflow: ellipsis;
  924. white-space: nowrap;
  925. }
  926. }
  927. .card-actions {
  928. padding: 16rpx 20rpx;
  929. display: flex;
  930. justify-content: flex-end;
  931. gap: 20rpx;
  932. border-top: 1rpx solid #eee;
  933. }
  934. .device-card {
  935. background: #fff;
  936. border-radius: 12rpx;
  937. margin-bottom: 20rpx;
  938. box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1);
  939. overflow: hidden;
  940. transition: all 0.3s ease;
  941. cursor: pointer;
  942. &.repair-card {
  943. border: 2rpx solid #f56c6c;
  944. background-color: rgba(245, 108, 108, 0.05);
  945. }
  946. }
  947. .card-header {
  948. padding: 16rpx 20rpx;
  949. background: #f5f7fa;
  950. border-bottom: 1rpx solid #eee;
  951. display: flex;
  952. justify-content: space-between;
  953. align-items: center;
  954. }
  955. .repair-tag {
  956. margin-left: 10rpx;
  957. }
  958. </style>