workOrderReport.vue 27 KB

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