workOrderReport.vue 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122
  1. <template>
  2. <u-popup
  3. :show="visible"
  4. :round="0"
  5. :closeOnClickOverlay="false"
  6. :zIndex="99999"
  7. @close="closePopup"
  8. class="u-popup-my"
  9. >
  10. <view class="popup-content">
  11. <view class="popup-header">
  12. <text class="popup-title">{{ title }}</text>
  13. <view class="close-btn" @click="closePopup">×</view>
  14. </view>
  15. <scroll-view class="popup-body" scroll-y>
  16. <view class="page">
  17. <view class="card-a">
  18. <!-- 头部 -->
  19. <view class="a-header">
  20. <text class="a-main-title">{{ form.ruleName }}</text>
  21. <view class="a-sub">
  22. <text
  23. >📋
  24. {{
  25. getDictValue("记录规则类型", form.recordRulesClassify)
  26. }}</text
  27. >
  28. </view>
  29. </view>
  30. <!-- 基本信息网格 -->
  31. <view class="info-grid">
  32. <view class="info-item">
  33. <text class="info-label">检查时间</text>
  34. <uni-datetime-picker
  35. type="datetime"
  36. v-model="form.checkStartTime"
  37. :disabled="title == '详情'"
  38. >
  39. <view class="info-value">{{
  40. form.checkStartTime || "请选择"
  41. }}</view>
  42. </uni-datetime-picker>
  43. </view>
  44. <view class="info-item">
  45. <text class="info-label">报工时间</text>
  46. <uni-datetime-picker
  47. type="datetime"
  48. v-model="form.checkFinishTime"
  49. :disabled="title == '详情'"
  50. >
  51. <view class="info-value">{{
  52. form.checkFinishTime || "请选择"
  53. }}</view>
  54. </uni-datetime-picker>
  55. </view>
  56. <view class="info-item" v-if="!form.type">
  57. <text class="info-label">部门</text>
  58. <view
  59. class="info-value"
  60. :class="{ disabled: title == '详情' }"
  61. @click="title != '详情' && $refs.treePicker._show()"
  62. >{{ form.groupName || "请选择" }}</view
  63. >
  64. </view>
  65. <view class="info-item" v-if="!form.type">
  66. <text class="info-label">指定负责人</text>
  67. <view
  68. class="info-value"
  69. :class="{ disabled: title == '详情' }"
  70. @click="title != '详情' && $refs.selector.open()"
  71. >{{
  72. form.executeUsers.map((item) => item.userName).toString() ||
  73. "请选择"
  74. }}</view
  75. >
  76. </view>
  77. <view class="info-item" v-if="form.type">
  78. <text class="info-label">班组</text>
  79. <view class="info-value">{{ form.teamName }}</view>
  80. </view>
  81. <view class="info-item" v-if="form.type">
  82. <text class="info-label">执行人</text>
  83. <view
  84. class="info-value"
  85. :class="{ disabled: title == '详情' }"
  86. @click="title != '详情' && $refs.selector.open()"
  87. >{{
  88. form.executeUsers.map((item) => item.userName).toString() ||
  89. "请选择"
  90. }}</view
  91. >
  92. </view>
  93. <view class="info-item" v-if="form.type">
  94. <text class="info-label">场站</text>
  95. <view
  96. class="info-value"
  97. :class="{ disabled: title == '详情' }"
  98. @click="title != '详情' && (showProductLineIdPicker = true)"
  99. >
  100. {{ form.productLineName || "请选择" }}
  101. </view>
  102. </view>
  103. <view
  104. class="info-item"
  105. v-if="pageName == 'steamInjectionInspectionRecord'"
  106. >
  107. <text class="info-label">甲方检查人</text>
  108. <view
  109. class="info-value"
  110. :class="{ disabled: title == '详情' }"
  111. @click="title != '详情' && selectContactShow(17)"
  112. >{{ form.contactName || "请选择" }}</view
  113. >
  114. </view>
  115. <view class="info-item" v-if="pageName == 'solidWasteRecord'">
  116. <text class="info-label">处理方</text>
  117. <view
  118. class="info-value"
  119. :class="{ disabled: title == '详情' }"
  120. @click="title != '详情' && selectContactShow(20)"
  121. >{{ form.supplierName || "请选择" }}</view
  122. >
  123. </view>
  124. <view class="info-item" v-if="pageName == 'qualityTestRecords'">
  125. <text class="info-label">甲方检查人</text>
  126. <view
  127. class="info-value"
  128. :class="{ disabled: title == '详情' }"
  129. @click="title != '详情' && selectContactShow(17)"
  130. >{{ form.contactName || "请选择" }}</view
  131. >
  132. </view>
  133. </view>
  134. <!-- 运行参数记录区 -->
  135. <view class="records-area">
  136. <view class="section-header">
  137. <view class="section-title">
  138. <text>📊 记录数据</text>
  139. </view>
  140. </view>
  141. <!-- 批量操作按钮放在标题下方 -->
  142. <view
  143. class="batch-bar"
  144. v-if="pageName != 'productionRecords' && title != '详情'"
  145. >
  146. <button class="btn btn-primary" @click="batchCheck">
  147. ✅ 批量检查
  148. </button>
  149. <button class="btn btn-secondary" @click="batchQualified">
  150. 🏭 批量合格
  151. </button>
  152. </view>
  153. <!-- 检查项列表 -->
  154. <view
  155. v-for="(item, idx) in form.detailList"
  156. :key="idx"
  157. class="check-item-a"
  158. >
  159. <view class="item-row1">
  160. <view class="item-info">
  161. <text class="item-name"
  162. >{{ idx + 1 }}. {{ item.paramValue }}
  163. {{ item.unitName ? "(" + item.unitName + ")" : "" }}</text
  164. >
  165. </view>
  166. </view>
  167. <view class="item-row-input" v-if="item.substanceName">
  168. <text class="input-label">设备</text>
  169. <view class="item-input"> {{ item.substanceName }}</view>
  170. </view>
  171. <!-- 描述/数量 -->
  172. <view class="item-row-input">
  173. <text class="input-label">{{
  174. pageName == "qualityTestRecords" ? "描述" : "数量"
  175. }}</text>
  176. <input
  177. class="item-input"
  178. v-model="item.num"
  179. type="text"
  180. placeholder="请输入数量"
  181. :disabled="title == '详情'"
  182. />
  183. </view>
  184. <view
  185. class="item-row-input"
  186. v-if="pageName == 'qualityTestRecords'"
  187. >
  188. <text class="input-label">执行人</text>
  189. <view
  190. class="info-value" style="padding:6px 10px;flex:1;border-radius: 28rpx;"
  191. :class="{ disabled: title == '详情' }"
  192. @click="title != '详情' && itemExecuteUsers(idx, item)"
  193. >{{
  194. (item.checkUsers &&
  195. item.checkUsers
  196. .map((item) => item.userName)
  197. .toString()) ||
  198. "请选择"
  199. }}</view
  200. >
  201. </view>
  202. <view
  203. class="item-actions"
  204. v-if="pageName != 'productionRecords'"
  205. >
  206. <u-radio-group
  207. class="result-group"
  208. v-model="item.checkStatus"
  209. :disabled="title == '详情'"
  210. >
  211. <u-radio label="已检查" :name="1"></u-radio>
  212. <u-radio label="未检查" :name="0"></u-radio>
  213. </u-radio-group>
  214. <u-radio-group
  215. class="result-group"
  216. v-model="item.checkResult"
  217. :disabled="title == '详情'"
  218. >
  219. <u-radio label="合格" :name="1"></u-radio>
  220. <u-radio label="不合格" :name="0"></u-radio>
  221. </u-radio-group>
  222. </view>
  223. </view>
  224. </view>
  225. </view>
  226. </view>
  227. </scroll-view>
  228. <view class="popup-footer">
  229. <u-button type="default" @click="closePopup">关闭</u-button>
  230. <u-button
  231. type="primary"
  232. @click="submit()"
  233. v-if="title == '报工'"
  234. :loading="loading"
  235. >提交</u-button
  236. >
  237. </view>
  238. </view>
  239. <u-toast ref="uToast"></u-toast>
  240. <ba-tree-picker
  241. ref="treePicker"
  242. key="verify"
  243. :multiple="false"
  244. @select-change="searchDeptNodeClick"
  245. title="选择部门"
  246. :localdata="classificationList"
  247. valueKey="id"
  248. textKey="name"
  249. childrenKey="children"
  250. />
  251. <search-select
  252. :multiple="true"
  253. ref="selector"
  254. v-model="form.executeUsersIds"
  255. :data-list="
  256. executorList.map((val) => {
  257. return {
  258. text: val.name,
  259. value: val.id,
  260. };
  261. })
  262. "
  263. title="选择"
  264. @confirm="executeIdListChange"
  265. >
  266. </search-select>
  267. <!-- 场站 -->
  268. <u-picker
  269. :show="showProductLineIdPicker"
  270. keyName="label"
  271. :columns="[
  272. productLineList.map((item) => {
  273. return {
  274. label: item.name,
  275. value: item.id,
  276. };
  277. }),
  278. ]"
  279. @confirm="confirmProductLine"
  280. @cancel="showProductLineIdPicker = false"
  281. ></u-picker>
  282. <search-select
  283. :multiple="true"
  284. ref="selector1"
  285. v-model="checkUsersIds"
  286. :data-list="
  287. (form.executeUsers &&
  288. form.executeUsers.map((val) => {
  289. return {
  290. text: val.userName,
  291. value: val.userId,
  292. };
  293. })) ||
  294. []
  295. "
  296. title="选择"
  297. @confirm="executeIdListChange1"
  298. >
  299. </search-select>
  300. <!-- <u-picker
  301. :show="showCheckUsersIds"
  302. keyName="label"
  303. mode="multiSelector"
  304. :columns="[
  305. form.executeUsers &&
  306. form.executeUsers.map((item) => {
  307. return {
  308. label: item.userName,
  309. value: item.userId,
  310. };
  311. }),
  312. ]"
  313. @confirm="confirmCheckUsersIds"
  314. @cancel="showCheckUsersIds = false"
  315. ></u-picker> -->
  316. </u-popup>
  317. </template>
  318. <script>
  319. const formBaseData = {
  320. id: null,
  321. workshopArea: "",
  322. workshopAreaId: null,
  323. checkFinishTime: "",
  324. checkStartTime: "",
  325. checkValidity: null,
  326. checkValidityUnit: "",
  327. conclusion: null,
  328. detailList: [],
  329. deviceId: 0,
  330. deviceName: "",
  331. batchNo: "",
  332. executeMethod: 0,
  333. formingNum: 0,
  334. itemType: 0,
  335. produceRoutingId: 0,
  336. produceRoutingName: "",
  337. produceTaskConfigId: 0,
  338. produceTaskId: 0,
  339. produceTaskName: "",
  340. productCode: "",
  341. productModel: "",
  342. productName: "",
  343. recordRulesClassify: null,
  344. recordTemplateStyle: null,
  345. ruleId: 0,
  346. ruleName: "",
  347. reportWorkType: 0,
  348. specification: "",
  349. workOrderCode: "",
  350. workOrderId: 0,
  351. itemTaskName: "",
  352. brandNo: "",
  353. duration: null,
  354. // 执行人
  355. executeUsersIds: [],
  356. executeUsers: [],
  357. showProductLineIdPicker: false,
  358. // 班组id
  359. teamId: "",
  360. groupId: null,
  361. // 物料字段name
  362. pickDetails: [],
  363. // 本次产出明细
  364. outputDetails: [],
  365. recordRulesExecuteMethodId: null,
  366. recordRulesExecuteMethodName: "",
  367. // 产出类型 1-原材料,2-在制品,3.BOM标准产出
  368. outputType: 1,
  369. type: 0,
  370. contactName: "",
  371. contactId: "",
  372. supplierId: "",
  373. supplierName: "",
  374. productLineId: null,
  375. productLineName: "",
  376. };
  377. import {
  378. getById,
  379. producetaskrulerecordSaveOrUpdateAndSubmit,
  380. } from "@/api/recordRules/index";
  381. import { getTeamPage } from "@/api/pda/workOrderHandover.js";
  382. import { getUserPage, listOrganizations } from "@/api/common.js";
  383. import { toTreeData } from "@/utils/utils.js";
  384. import { mapGetters } from "vuex";
  385. import searchSelect from "@/pages/salesServiceManagement/accessory/components/searchSelect.vue";
  386. export default {
  387. data() {
  388. return {
  389. visible: false,
  390. executeUsersIds: [],
  391. title: "",
  392. loading: false,
  393. butLoading: false,
  394. checked: false,
  395. teamUserList: [],
  396. teamList: [],
  397. teamAllList: [],
  398. classificationList: [],
  399. showProductLineIdPicker: false,
  400. showCheckUsersIds: false,
  401. executorList: [],
  402. allTeamList: [],
  403. productLineList: [],
  404. currentIndex: "",
  405. form: JSON.parse(JSON.stringify(formBaseData)),
  406. };
  407. },
  408. computed: {
  409. ...mapGetters(["getDictValue"]),
  410. },
  411. components: {
  412. searchSelect,
  413. },
  414. props: {
  415. pageName: "",
  416. },
  417. methods: {
  418. async open(row, type) {
  419. uni.$off("setSelectList");
  420. uni.$on("setSelectList", (data) => {
  421. console.log(data, "data");
  422. if (data && data.length > 0) {
  423. this.form.contactName = data[0].name;
  424. this.form.contactId = data[0].id;
  425. this.form.supplierName = data[0].name;
  426. this.form.supplierId = data[0].id;
  427. }
  428. });
  429. if (type == "edit") {
  430. this.title = "报工";
  431. } else {
  432. this.title = "详情";
  433. }
  434. this.getTreeList();
  435. await this.getOrderDetials(row.id);
  436. this.visible = true;
  437. },
  438. cancel() {
  439. this.form = {
  440. ...JSON.parse(JSON.stringify(formBaseData)),
  441. };
  442. this.visible = false;
  443. },
  444. async getTreeList() {
  445. const data = await listOrganizations({});
  446. let treeList = toTreeData({
  447. data: data || [],
  448. idField: "id",
  449. parentIdField: "parentId",
  450. });
  451. this.classificationList = treeList;
  452. },
  453. selectContactShow(type) {
  454. uni.navigateTo({
  455. url:
  456. "/pages/saleManage/components/selectContact?isAll=" +
  457. false +
  458. "&contactType=" +
  459. type,
  460. });
  461. },
  462. confirmProductLine(e) {
  463. this.form.productLineId = e.value[0].value;
  464. this.form.productLineName = e.value[0].label;
  465. this.showProductLineIdPicker = false;
  466. },
  467. closePopup() {
  468. this.cancel();
  469. },
  470. handParent() {
  471. this.$refs.parentListRef.open();
  472. },
  473. changeParent(data) {
  474. this.form.contactName = data.name;
  475. this.form.contactId = data.id;
  476. this.form.supplierName = data.name;
  477. this.form.supplierId = data.id;
  478. },
  479. // 获取工单详情
  480. async getOrderDetials(id) {
  481. try {
  482. const data = await getById(id);
  483. data.detailList = data.detailList.map((i) => {
  484. i.toolNames = i.tools.map((j) => j.toolName).join(",");
  485. if (i.checkUsers && i.checkUsers.length > 0) {
  486. console.log("i.checkUsers", i.checkUsers);
  487. i.checkUsersIds = i.checkUsers.map((j) => j.userId);
  488. }
  489. if (i.checkUsersIds?.length == 0 && data.executeUsers.length > 0) {
  490. // 默认执行人作为检查人
  491. i.checkUsersIds = data.executeUsers
  492. .filter((i) => i.userId)
  493. .map((j) => j.userId);
  494. i.checkUsers = data.executeUsers
  495. .filter((i) => i.userId)
  496. .map((j) => {
  497. return {
  498. teamId: j.teamId,
  499. teamName: j.teamName,
  500. userId: j.userId,
  501. userName: j.userName,
  502. };
  503. });
  504. }
  505. return i;
  506. });
  507. // this.$util.assignObject(this.form, data);
  508. Object.assign(this.form, data);
  509. this.form.executeUsersIds = this.form.executeUsers
  510. .map((i) => i.userId)
  511. .filter((i) => i); // 过滤掉 undefined
  512. if (this.form.executeUsers.length > 0 && !this.form.type) {
  513. this.form.groupId = this.form.executeUsers[0]?.groupId + "";
  514. this.form.groupName = this.form.executeUsers[0]?.groupName;
  515. if (this.form.groupId) {
  516. this.searchDeptNodeClick(
  517. this.form.groupId,
  518. this.form.groupName,
  519. "init",
  520. );
  521. }
  522. }
  523. if (!this.form.teamId && this.teamList.length > 0) {
  524. this.form.teamId = this.teamList[0].id;
  525. }
  526. this.form.recordRulesClassify += "";
  527. // 加载班组人员列表
  528. if (this.form.teamId && this.form.type) {
  529. await this.getAllTeamList();
  530. const index = this.allTeamList.findIndex(
  531. (item) => item.id == this.form.teamId,
  532. );
  533. this.executorList = this.allTeamList[index].userVOList;
  534. this.productLineList = [];
  535. this.allTeamList[index].factoryWorkstationVOList.forEach((item) => {
  536. if (
  537. !this.productLineList.find((p) => p.id === item.productionLineId)
  538. ) {
  539. this.productLineList.push({
  540. name: item.productionLineName,
  541. id: item.productionLineId,
  542. });
  543. }
  544. });
  545. }
  546. this.$nextTick(() => {
  547. this.loading = false;
  548. });
  549. } catch (error) {
  550. console.log("error", error);
  551. this.loading = false;
  552. }
  553. },
  554. checkTeamList(id) {
  555. const index = this.teamList.findIndex((item) => item.id == id);
  556. this.teamUserList = this.teamAllList[index];
  557. this.form.teamName = this.teamList[index].name;
  558. console.log("this.teamUserList", this.teamUserList);
  559. },
  560. // 批量检查
  561. batchCheck() {
  562. this.form.detailList.forEach((i, index) => {
  563. this.$set(this.form.detailList[index], "checkStatus", 1);
  564. });
  565. },
  566. // 批量合格
  567. batchQualified() {
  568. this.form.detailList.forEach((i, index) => {
  569. this.$set(this.form.detailList[index], "checkResult", 1);
  570. });
  571. },
  572. itemExecuteUsers(index, row) {
  573. this.currentIndex = index;
  574. this.$refs.selector1.open();
  575. },
  576. executeIdListChange1() {
  577. this.$set(
  578. this.form.detailList[this.currentIndex],
  579. "checkUsersIds",
  580. this.checkUsersIds,
  581. );
  582. const checkUsersIds = this.checkUsersIds;
  583. this.checkUsersIds = [];
  584. const checkUsers = checkUsersIds.map((i) => {
  585. const user = this.form.executeUsers.find((item) => item.userId === i);
  586. return user;
  587. });
  588. console.log(checkUsers, "checkUsers");
  589. this.$set(
  590. this.form.detailList[this.currentIndex],
  591. "checkUsers",
  592. checkUsers,
  593. );
  594. },
  595. // 获取审核人列表、巡点检人员
  596. async getUserList(params) {
  597. try {
  598. let data = {
  599. pageNum: 1,
  600. size: -1,
  601. };
  602. // 如果传了参数就是获取部门人员数据
  603. if (params) {
  604. data = Object.assign(data, params);
  605. }
  606. const res = await getUserPage(data);
  607. if (params) {
  608. this.executorList = res.list;
  609. }
  610. } catch (error) {}
  611. },
  612. //选择部门(搜索)
  613. async searchDeptNodeClick(id, name, type) {
  614. this.form.groupId = id;
  615. this.form.groupName = name;
  616. if (id) {
  617. // 根据部门获取人员
  618. const params = {
  619. groupId: id,
  620. };
  621. await this.getUserList(params);
  622. } else {
  623. this.form.groupId = null;
  624. }
  625. if (type != "init") {
  626. this.form.detailList.forEach((detail) => {
  627. detail.checkUsersIds = [];
  628. detail.checkUsers = [];
  629. });
  630. this.form.executeUsers = [];
  631. this.form.executeUsersIds = [];
  632. }
  633. },
  634. // 负责人变更 同步执行人列表
  635. executeIdListChange() {
  636. console.log(this.form.executeUsersIds, "this.form.executeUsersIds");
  637. this.form.executeUsers = this.form.executeUsersIds
  638. .map((userId) => {
  639. const user = this.executorList.find((u) => u.id === userId);
  640. if (!user) return null;
  641. return {
  642. userId: user.id,
  643. userName: user.name,
  644. groupId: user.groupId,
  645. groupName: user.groupName,
  646. };
  647. })
  648. .filter((i) => i);
  649. // 同步详情执行人
  650. this.form.detailList.forEach((detail, index) => {
  651. this.$set(
  652. this.form.detailList[index],
  653. "checkUsersIds",
  654. this.form.executeUsersIds,
  655. );
  656. this.$set(
  657. this.form.detailList[index],
  658. "checkUsers",
  659. this.form.executeUsers,
  660. );
  661. });
  662. console.log("this.form.executeUsers", this.form.detailList);
  663. },
  664. async getAllTeamList() {
  665. const { list } = await getTeamPage({
  666. pageNum: 1,
  667. size: -1,
  668. });
  669. console.log("teamAllList 班组", list);
  670. this.allTeamList = list;
  671. },
  672. // 提交
  673. async submit() {
  674. // 验证检查时间和报工时间必填
  675. if (!this.form.checkStartTime) {
  676. this.$refs.uToast.show({
  677. type: "error",
  678. icon: false,
  679. message: `请选择检查时间`,
  680. });
  681. return;
  682. }
  683. if (!this.form.checkFinishTime) {
  684. this.$refs.uToast.show({
  685. type: "error",
  686. icon: false,
  687. message: `请选择报工时间`,
  688. });
  689. return;
  690. }
  691. // 验证报工时间必须大于等于检查时间
  692. const startTime = new Date(this.form.checkStartTime).getTime();
  693. const finishTime = new Date(this.form.checkFinishTime).getTime();
  694. if (finishTime < startTime) {
  695. this.$refs.uToast.show({
  696. type: "error",
  697. icon: false,
  698. message: `报工时间不能早于检查时间`,
  699. });
  700. return;
  701. }
  702. if (this.form.executeUsersIds.length == 0) {
  703. this.$refs.uToast.show({
  704. type: "error",
  705. icon: false,
  706. message: `请选择执行人`,
  707. });
  708. return;
  709. }
  710. // 报工需要验证 缓存不验证 排除 recordTemplateStyle ==3 物料添加 == 4生产统计 模板
  711. if (this.pageName != "productionRecords") {
  712. // 验证检查项目
  713. const detailRequired = this.form.detailList.some((i) => {
  714. return i.checkResult == null || i.checkStatus == null;
  715. });
  716. if (detailRequired) {
  717. this.$refs.uToast.show({
  718. type: "error",
  719. icon: false,
  720. message: `请先完善、检查情况、检查结果`,
  721. });
  722. return;
  723. }
  724. }
  725. const body = JSON.parse(JSON.stringify(this.form));
  726. try {
  727. await producetaskrulerecordSaveOrUpdateAndSubmit(body);
  728. this.$emit("refresh");
  729. this.closePopup();
  730. } catch (error) {
  731. console.log(error, "dsdsd");
  732. }
  733. },
  734. },
  735. };
  736. </script>
  737. <style scoped lang="scss">
  738. .popup-content {
  739. width: 100vw;
  740. height: calc(100vh - 100px);
  741. background: #fff;
  742. border-radius: 0;
  743. display: flex;
  744. background-color: #eff2f7;
  745. flex-direction: column;
  746. }
  747. .popup-header {
  748. display: flex;
  749. justify-content: space-between;
  750. align-items: center;
  751. padding: 30rpx;
  752. border-bottom: 1rpx solid #e5e5e5;
  753. .popup-title {
  754. font-size: 36rpx;
  755. font-weight: bold;
  756. color: #333;
  757. }
  758. .close-btn {
  759. width: 60rpx;
  760. height: 60rpx;
  761. display: flex;
  762. align-items: center;
  763. justify-content: center;
  764. font-size: 60rpx;
  765. color: #999;
  766. line-height: 1;
  767. }
  768. }
  769. .popup-body {
  770. flex: 1;
  771. overflow-y: auto;
  772. padding: 28rpx;
  773. }
  774. .page {
  775. font-family:
  776. system-ui,
  777. -apple-system,
  778. "Segoe UI",
  779. Roboto,
  780. Helvetica,
  781. sans-serif;
  782. }
  783. .design-section {
  784. /* margin-bottom: 60rpx; */
  785. }
  786. .design-header {
  787. margin-bottom: 20rpx;
  788. padding-left: 8rpx;
  789. }
  790. .design-title {
  791. font-size: 44rpx;
  792. font-weight: 800;
  793. color: #1f2b3c;
  794. display: block;
  795. }
  796. .design-desc {
  797. font-size: 26rpx;
  798. color: #6b7280;
  799. margin-top: 6rpx;
  800. }
  801. /* 卡片白色风格 */
  802. .card-a {
  803. background: #ffffff;
  804. border-radius: 48rpx;
  805. box-shadow: 0 12rpx 40rpx rgba(0, 0, 0, 0.05);
  806. overflow: hidden;
  807. }
  808. .a-header {
  809. padding: 40rpx 32rpx 24rpx;
  810. border-bottom: 2rpx solid #f0f2f5;
  811. }
  812. .a-main-title {
  813. font-size: 36rpx;
  814. font-weight: 800;
  815. background: linear-gradient(135deg, #1f2b3c, #2c3e50);
  816. background-clip: text;
  817. -webkit-background-clip: text;
  818. color: transparent;
  819. letter-spacing: -0.5rpx;
  820. }
  821. .a-sub {
  822. font-size: 24rpx;
  823. color: #8e9aae;
  824. margin-top: 12rpx;
  825. display: flex;
  826. gap: 24rpx;
  827. }
  828. .info-grid {
  829. padding: 30rpx 32rpx;
  830. display: grid;
  831. grid-template-columns: 1fr 1fr;
  832. gap: 28rpx 20rpx;
  833. // background: #fcfdfe;
  834. border-bottom: 2rpx solid #f0f2f5;
  835. }
  836. .info-item {
  837. display: flex;
  838. flex-direction: column;
  839. gap: 8rpx;
  840. }
  841. .info-label {
  842. font-size: 26rpx;
  843. font-weight: 600;
  844. color: #6c7a91;
  845. text-transform: uppercase;
  846. }
  847. .records-area {
  848. padding: 16rpx 28rpx 32rpx;
  849. }
  850. .section-header {
  851. display: flex;
  852. justify-content: space-between;
  853. align-items: center;
  854. margin: 16rpx 0 20rpx 8rpx;
  855. }
  856. .section-title {
  857. font-size: 36rpx;
  858. font-weight: 700;
  859. color: #1f2a44;
  860. display: flex;
  861. align-items: center;
  862. gap: 16rpx;
  863. }
  864. .badge {
  865. background: #eff3fa;
  866. padding: 6rpx 20rpx;
  867. border-radius: 60rpx;
  868. font-size: 24rpx;
  869. font-weight: normal;
  870. color: #2c5f8a;
  871. }
  872. .device-card-a {
  873. background: #f8fbfe;
  874. border-radius: 36rpx;
  875. padding: 20rpx 24rpx;
  876. margin-bottom: 30rpx;
  877. display: flex;
  878. align-items: center;
  879. justify-content: space-between;
  880. flex-wrap: wrap;
  881. border: 2rpx solid #e9edf2;
  882. }
  883. .device-label {
  884. font-weight: 700;
  885. font-size: 28rpx;
  886. color: #1f2a44;
  887. background: #eff3fa;
  888. padding: 8rpx 24rpx;
  889. border-radius: 60rpx;
  890. }
  891. .device-input-a {
  892. flex: 1;
  893. min-width: 280rpx;
  894. background: #ffffff;
  895. border: 2rpx solid #dce3ec;
  896. border-radius: 36rpx;
  897. padding: 16rpx 24rpx;
  898. font-size: 28rpx;
  899. }
  900. .check-item-a {
  901. background: #ffffff;
  902. border-radius: 36rpx;
  903. padding: 24rpx 24rpx;
  904. margin-bottom: 24rpx;
  905. box-shadow:
  906. 0 4rpx 16rpx rgba(0, 0, 0, 0.02),
  907. 0 0 0 2rpx #edf2f7;
  908. }
  909. .item-row1 {
  910. display: flex;
  911. justify-content: space-between;
  912. align-items: baseline;
  913. flex-wrap: wrap;
  914. margin-bottom: 20rpx;
  915. gap: 16rpx;
  916. }
  917. .item-name {
  918. font-weight: 620;
  919. font-size: 30rpx;
  920. color: #1f2a44;
  921. background: #f5f7fb;
  922. padding: 6rpx 20rpx;
  923. border-radius: 50rpx;
  924. }
  925. .item-info {
  926. display: flex;
  927. flex-direction: column;
  928. gap: 8rpx;
  929. }
  930. .item-row-input {
  931. display: flex;
  932. align-items: center;
  933. gap: 16rpx;
  934. margin-bottom: 20rpx;
  935. padding: 0 8rpx;
  936. }
  937. .input-label {
  938. font-size: 28rpx;
  939. color: #555;
  940. font-weight: 500;
  941. white-space: nowrap;
  942. }
  943. .item-input {
  944. // background: #f8fafe;
  945. border: 2rpx solid #e2e8f0;
  946. border-radius: 36rpx;
  947. padding: 12rpx 24rpx;
  948. font-size: 30rpx;
  949. height: 60rpx;
  950. flex: 1;
  951. font-family: monospace;
  952. }
  953. .item-actions {
  954. display: flex;
  955. justify-content: space-between;
  956. align-items: center;
  957. flex-wrap: wrap;
  958. gap: 20rpx;
  959. }
  960. .check-status,
  961. .result-group {
  962. display: flex;
  963. align-items: center;
  964. gap: 24rpx;
  965. background: #f8fafe;
  966. padding: 8rpx 24rpx;
  967. border-radius: 60rpx;
  968. font-size: 28rpx;
  969. }
  970. /deep/.result-group {
  971. .u-radio__text {
  972. font-size: 28rpx !important;
  973. }
  974. .u-radio__icon-wrap {
  975. width: 30rpx !important;
  976. height: 30rpx !important;
  977. }
  978. }
  979. .radio-label {
  980. display: flex;
  981. align-items: center;
  982. gap: 8rpx;
  983. }
  984. .batch-bar {
  985. display: flex;
  986. gap: 16rpx;
  987. margin: 16rpx 0 20rpx 8rpx;
  988. }
  989. .btn {
  990. flex: 1;
  991. text-align: center;
  992. border-radius: 80rpx;
  993. font-weight: 700;
  994. font-size: 30rpx;
  995. border: none;
  996. }
  997. .btn-primary {
  998. background: #1e6f5c;
  999. color: white;
  1000. box-shadow: 0 4rpx 12rpx rgba(30, 111, 92, 0.2);
  1001. }
  1002. .btn-secondary {
  1003. background: #2c7da0;
  1004. color: white;
  1005. }
  1006. .footnote {
  1007. font-size: 22rpx;
  1008. color: #8e9aab;
  1009. text-align: center;
  1010. margin-top: 16rpx;
  1011. display: block;
  1012. }
  1013. /* 修复组件样式 */
  1014. radio,
  1015. checkbox {
  1016. transform: scale(0.9);
  1017. margin-right: 6rpx;
  1018. }
  1019. button:after {
  1020. border: none;
  1021. }
  1022. .info-value {
  1023. font-size: 28rpx;
  1024. font-weight: 500;
  1025. color: #1e2a3a;
  1026. // background: #f2f5f9;
  1027. padding: 16rpx 20rpx;
  1028. border-radius: 24rpx;
  1029. border: 2rpx solid #e9edf2;
  1030. &.disabled {
  1031. color: #999;
  1032. background: #f5f5f5;
  1033. }
  1034. }
  1035. .popup-footer {
  1036. display: flex;
  1037. padding: 20rpx 30rpx;
  1038. border-top: 1rpx solid #e5e5e5;
  1039. gap: 20rpx;
  1040. /deep/ .u-button {
  1041. flex: 1;
  1042. }
  1043. }
  1044. /deep/.uni-select {
  1045. border-radius: 36rpx;
  1046. }
  1047. </style>