detail.vue 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952
  1. <template>
  2. <view class="content-box">
  3. <uni-nav-bar
  4. fixed="true"
  5. statusBar="true"
  6. left-icon="back"
  7. title="不合格品处置"
  8. background-color="#157A2C"
  9. color="#fff"
  10. @clickLeft="back"
  11. ></uni-nav-bar>
  12. <view class="list_box">
  13. <u-list @scrolltolower="() => {}" key="list">
  14. <u-list-item v-for="(item, index) in poList" :key="index">
  15. <view class="card_box">
  16. <view class="header rx-sc">
  17. <view
  18. class="checkbox-wrap"
  19. v-if="item.disposalStatus !== 2 && showBtn"
  20. @click.stop="toggleCheck(item)"
  21. >
  22. <u-checkbox-group>
  23. <u-checkbox
  24. :checked="isChecked(item)"
  25. shape="square"
  26. size="36rpx"
  27. activeColor="#157A2C"
  28. @change="toggleCheck(item)"
  29. ></u-checkbox>
  30. </u-checkbox-group>
  31. </view>
  32. <view class="round">{{ index + 1 }}</view>
  33. <view class="orderId">{{ item.categoryName }}</view>
  34. <view
  35. class="status-tag"
  36. :class="'status-' + (item.disposalStatus || 0)"
  37. >
  38. {{ disposalStatusMap[item.disposalStatus || 0] }}
  39. </view>
  40. </view>
  41. <view class="row">
  42. <view class="label">样品编码</view>
  43. <view class="value">{{ item.sampleCode }}</view>
  44. </view>
  45. <view class="row">
  46. <view class="label">物品编码</view>
  47. <view class="value">{{ item.categoryCode }}</view>
  48. </view>
  49. <view class="row">
  50. <view class="label">规格</view>
  51. <view class="value">{{ item.specification }}</view>
  52. </view>
  53. <view class="row">
  54. <view class="label">牌号</view>
  55. <view class="value">{{ item.brandNum }}</view>
  56. </view>
  57. <view class="row">
  58. <view class="label">型号</view>
  59. <view class="value">{{ item.modelType }}</view>
  60. </view>
  61. <view class="row">
  62. <view class="label">批次号</view>
  63. <view class="value">{{ item.batchNo }}</view>
  64. </view>
  65. <view class="row">
  66. <view class="label">计量数量</view>
  67. <view class="value"
  68. >{{ item.measureQuantity }}{{ item.measureUnit }}</view
  69. >
  70. </view>
  71. <view class="row">
  72. <view class="label">不良类型</view>
  73. <view class="value">{{ item.badTypeName }}</view>
  74. </view>
  75. <view class="row">
  76. <view class="label">不良名称</view>
  77. <view class="value">{{ item.badNameName }}</view>
  78. </view>
  79. <view class="row">
  80. <view class="label">原因类型</view>
  81. <view class="value">{{ item.reasonTypeName }}</view>
  82. </view>
  83. <view class="row">
  84. <view class="label">原因</view>
  85. <view class="value">{{ item.unqualifiedReason }}</view>
  86. </view>
  87. <view class="row" v-if="item.disposeType">
  88. <view class="label">处置类型</view>
  89. <view class="value">{{
  90. getDisposeTypeName(item.disposeType)
  91. }}</view>
  92. </view>
  93. <view class="row" v-if="item.disposeTime">
  94. <view class="label">处置时间</view>
  95. <view class="value">{{ item.disposeTime }}</view>
  96. </view>
  97. <view class="btn-row" v-if="item.disposalStatus !== 2 && showBtn">
  98. <button class="btn-dispose" @click="disposeFn(2, item)">
  99. 处置
  100. </button>
  101. <button class="btn-delete" @click="confirmDelete(item)">
  102. 删除
  103. </button>
  104. </view>
  105. </view>
  106. </u-list-item>
  107. <u-list-item v-if="poList.length === 0 && !loading">
  108. <view style="margin-top: 20vh">
  109. <u-empty iconSize="150" textSize="32" text="暂无明细数据">
  110. </u-empty>
  111. </view>
  112. </u-list-item>
  113. </u-list>
  114. </view>
  115. <!-- 底部批量操作栏 -->
  116. <view class="footer-bar" v-if="showBtn">
  117. <view class="footer-left" @click="toggleSelectAll">
  118. <u-checkbox-group>
  119. <u-checkbox
  120. :checked="isAllChecked"
  121. shape="square"
  122. size="36rpx"
  123. activeColor="#157A2C"
  124. @change="toggleSelectAll"
  125. ></u-checkbox>
  126. </u-checkbox-group>
  127. <text class="select-all-text">全选</text>
  128. </view>
  129. <button
  130. class="btn-batch"
  131. :disabled="selection.length === 0"
  132. @click="disposeFn(1)"
  133. >
  134. 批量处置{{ selection.length > 0 ? "(" + selection.length + ")" : "" }}
  135. </button>
  136. </view>
  137. <!-- 处置弹窗 -->
  138. <u-popup
  139. :show="dialogVisible"
  140. mode="bottom"
  141. round="24"
  142. @close="closeDialog"
  143. >
  144. <view class="popup-content">
  145. <view class="popup-header">
  146. <text class="popup-title">处置</text>
  147. <text class="popup-close" @click="closeDialog">✕</text>
  148. </view>
  149. <!-- 处置方式 -->
  150. <view class="form-item">
  151. <view class="form-label required">处置方式</view>
  152. <view class="picker-box" @click="showDisposePicker = true">
  153. <text :class="{ placeholder: !disposeForm.disposeType }">
  154. {{ disposeTypeName || "请选择处置方式" }}
  155. </text>
  156. <text class="arrow">▸</text>
  157. </view>
  158. </view>
  159. <!-- 回流工序 (返工=1/返修=2) -->
  160. <template
  161. v-if="disposeForm.disposeType == 1 || disposeForm.disposeType == 2"
  162. >
  163. <view class="form-item">
  164. <view class="form-label">回流工序</view>
  165. <view class="picker-box" @click="showRefluxPicker = true">
  166. <text :class="{ placeholder: !disposeForm.taskId }">
  167. {{ refluxTaskName || "请选择回流工序" }}
  168. </text>
  169. <text class="arrow">▸</text>
  170. </view>
  171. </view>
  172. </template>
  173. <!-- 留样字段 (disposeType=6) -->
  174. <template v-if="disposeForm.disposeType == 6">
  175. <view class="form-item">
  176. <view class="form-label">留样数量</view>
  177. <view class="input-box">
  178. <input
  179. type="digit"
  180. v-model="disposeForm.keepSampleQuantity"
  181. placeholder="请输入留样数量"
  182. />
  183. <text class="unit" v-if="current && current.measureUnit">{{
  184. current.measureUnit
  185. }}</text>
  186. </view>
  187. </view>
  188. <view class="form-item">
  189. <view class="form-label">留样日期</view>
  190. <view class="picker-box" @click="showDatePicker = true">
  191. <text :class="{ placeholder: !disposeForm.sampleDate }">
  192. {{ disposeForm.sampleDate || "请选择日期" }}
  193. </text>
  194. <text class="arrow">▸</text>
  195. </view>
  196. </view>
  197. <view class="form-item">
  198. <view class="form-label">留样条件</view>
  199. <view class="input-box">
  200. <input
  201. v-model="disposeForm.sampleCondition"
  202. placeholder="请输入留样条件"
  203. />
  204. </view>
  205. </view>
  206. <view class="form-item">
  207. <view class="form-label">生产商/受托生产</view>
  208. <view class="input-box">
  209. <input
  210. v-model="disposeForm.producerManufacturer"
  211. placeholder="请输入"
  212. />
  213. </view>
  214. </view>
  215. <view class="form-item">
  216. <view class="form-label">留样地点</view>
  217. <view class="input-box">
  218. <textarea
  219. v-model="disposeForm.samplePlace"
  220. placeholder="请输入留样地点"
  221. :auto-height="true"
  222. />
  223. </view>
  224. </view>
  225. <view class="form-item">
  226. <view class="form-label">留样备注</view>
  227. <view class="input-box">
  228. <textarea
  229. v-model="disposeForm.sampleRemark"
  230. placeholder="请输入留样备注"
  231. :auto-height="true"
  232. />
  233. </view>
  234. </view>
  235. </template>
  236. <!-- 入库仓库 (报废=3/留样=6/转试销=9) -->
  237. <template
  238. v-if="
  239. disposeForm.disposeType == 3 ||
  240. disposeForm.disposeType == 6 ||
  241. disposeForm.disposeType == 9
  242. "
  243. >
  244. <view class="form-item">
  245. <view
  246. class="form-label"
  247. :class="{ required: disposeForm.disposeType != 6 }"
  248. >入库仓库</view
  249. >
  250. <view class="picker-box" @click="showWarehousePicker = true">
  251. <text :class="{ placeholder: !disposeForm.depotId }">
  252. {{ disposeForm.depotName || "请选择仓库" }}
  253. </text>
  254. <text class="arrow">▸</text>
  255. </view>
  256. </view>
  257. </template>
  258. <view class="popup-footer">
  259. <button class="btn-cancel" @click="closeDialog">取消</button>
  260. <button class="btn-confirm" @click="handleDispose">确定</button>
  261. </view>
  262. </view>
  263. </u-popup>
  264. <!-- 处置方式选择器 -->
  265. <u-picker
  266. :show="showDisposePicker"
  267. :columns="[disposePickerColumns]"
  268. keyName="label"
  269. @confirm="onDisposeConfirm"
  270. @cancel="showDisposePicker = false"
  271. @close="showDisposePicker = false"
  272. ></u-picker>
  273. <!-- 回流工序选择器 -->
  274. <u-picker
  275. :show="showRefluxPicker"
  276. :columns="[refluxPickerColumns]"
  277. keyName="taskTypeName"
  278. @confirm="onRefluxConfirm"
  279. @cancel="showRefluxPicker = false"
  280. @close="showRefluxPicker = false"
  281. ></u-picker>
  282. <!-- 仓库选择器 -->
  283. <u-picker
  284. :show="showWarehousePicker"
  285. :columns="[warehousePickerColumns]"
  286. keyName="name"
  287. @confirm="onWarehouseConfirm"
  288. @cancel="showWarehousePicker = false"
  289. @close="showWarehousePicker = false"
  290. ></u-picker>
  291. <!-- 日期选择器 -->
  292. <u-datetime-picker
  293. :show="showDatePicker"
  294. mode="date"
  295. @confirm="onDateConfirm"
  296. @cancel="showDatePicker = false"
  297. @close="showDatePicker = false"
  298. ></u-datetime-picker>
  299. </view>
  300. </template>
  301. <script>
  302. import {
  303. getById,
  304. disposeApi,
  305. refluxTask,
  306. getWarehouseList,
  307. deleteUnacceptedProductDetail,
  308. } from "@/api/pda/nonconforming.js";
  309. export default {
  310. data() {
  311. return {
  312. id: "",
  313. qualityType: null,
  314. workOrderCode: "",
  315. viewType: "",
  316. loading: false,
  317. poList: [],
  318. selection: [],
  319. dialogVisible: false,
  320. isBatch: false,
  321. current: null,
  322. disposeForm: {
  323. disposeType: "",
  324. sampleCondition: "",
  325. sampleDate: "",
  326. samplePlace: "",
  327. sampleRemark: "",
  328. producerManufacturer: "",
  329. depotId: "",
  330. depotName: "",
  331. taskId: "",
  332. keepSampleQuantity: "",
  333. },
  334. allList: [
  335. { value: 1, label: "返工" },
  336. { value: 2, label: "返修" },
  337. { value: 3, label: "报废" },
  338. { value: 4, label: "降级使用" },
  339. { value: 5, label: "让步接收" },
  340. { value: 6, label: "留样" },
  341. { value: 7, label: "消耗" },
  342. { value: 8, label: "回用/归批" },
  343. { value: 9, label: "转试销" },
  344. { value: 10, label: "退货" },
  345. ],
  346. warehouseList: [],
  347. refluxTaskList: [],
  348. showDisposePicker: false,
  349. showRefluxPicker: false,
  350. showWarehousePicker: false,
  351. showDatePicker: false,
  352. disposalStatusMap: { 0: "待处置", 1: "处置中", 2: "处置完成" },
  353. };
  354. },
  355. computed: {
  356. showBtn() {
  357. return this.viewType !== "detail";
  358. },
  359. canDisposeList() {
  360. return this.poList.filter((item) => item.disposalStatus !== 2);
  361. },
  362. isAllChecked() {
  363. return (
  364. this.canDisposeList.length > 0 &&
  365. this.selection.length === this.canDisposeList.length
  366. );
  367. },
  368. disposeList() {
  369. if (this.qualityType == 1) {
  370. return this.allList.filter((item) => [5, 10].includes(item.value));
  371. }
  372. if (this.qualityType == 3) {
  373. return this.allList.filter(
  374. (item) => item.value !== 8 && item.value !== 10,
  375. );
  376. }
  377. if (this.qualityType == 2) {
  378. return this.allList.filter((item) => item.value !== 8);
  379. }
  380. return this.allList;
  381. },
  382. disposePickerColumns() {
  383. return this.disposeList;
  384. },
  385. refluxPickerColumns() {
  386. return this.refluxTaskList;
  387. },
  388. warehousePickerColumns() {
  389. return this.warehouseList;
  390. },
  391. disposeTypeName() {
  392. const found = this.allList.find(
  393. (item) => item.value == this.disposeForm.disposeType,
  394. );
  395. return found ? found.label : "";
  396. },
  397. refluxTaskName() {
  398. const found = this.refluxTaskList.find(
  399. (item) => item.taskId == this.disposeForm.taskId,
  400. );
  401. return found ? found.taskTypeName : "";
  402. },
  403. },
  404. onLoad(option) {
  405. this.id = option.id;
  406. this.qualityType = option.qualityType;
  407. this.workOrderCode = option.workOrderCode || "";
  408. this.viewType = option.type || "";
  409. },
  410. onShow() {
  411. this.loadData();
  412. },
  413. methods: {
  414. back() {
  415. uni.navigateBack();
  416. },
  417. async loadData() {
  418. this.loading = true;
  419. this.selection = [];
  420. try {
  421. const res = await getById(this.id);
  422. this.poList = res.poList || [];
  423. if (this.workOrderCode) {
  424. this.getRefluxTask();
  425. }
  426. this.loadWarehouse();
  427. } catch (e) {
  428. uni.showToast({ title: "加载失败", icon: "none" });
  429. } finally {
  430. this.loading = false;
  431. }
  432. },
  433. async loadWarehouse() {
  434. try {
  435. this.warehouseList = await getWarehouseList();
  436. } catch (e) {
  437. this.warehouseList = [];
  438. }
  439. },
  440. async getRefluxTask() {
  441. try {
  442. const res = await refluxTask({ workOrderCode: this.workOrderCode });
  443. this.refluxTaskList = res || [];
  444. } catch (e) {
  445. this.refluxTaskList = [];
  446. }
  447. },
  448. getDisposeTypeName(val) {
  449. const found = this.allList.find((item) => item.value == val);
  450. return found ? found.label : "";
  451. },
  452. isChecked(item) {
  453. return this.selection.some((s) => s.id === item.id);
  454. },
  455. toggleCheck(item) {
  456. const idx = this.selection.findIndex((s) => s.id === item.id);
  457. if (idx > -1) {
  458. this.selection.splice(idx, 1);
  459. } else {
  460. this.selection.push(item);
  461. }
  462. },
  463. toggleSelectAll() {
  464. if (this.isAllChecked) {
  465. this.selection = [];
  466. } else {
  467. this.selection = [...this.canDisposeList];
  468. }
  469. },
  470. disposeFn(type, row) {
  471. if (type == 1) {
  472. if (this.selection.length === 0) {
  473. uni.showToast({ title: "请先勾选需要处置的数据", icon: "none" });
  474. return;
  475. }
  476. this.isBatch = true;
  477. } else {
  478. this.isBatch = false;
  479. this.current = row;
  480. }
  481. this.resetDisposeForm();
  482. this.dialogVisible = true;
  483. },
  484. resetDisposeForm() {
  485. this.disposeForm = {
  486. disposeType: "",
  487. sampleCondition: "",
  488. sampleDate: "",
  489. samplePlace: "",
  490. sampleRemark: "",
  491. producerManufacturer: "",
  492. depotId: "",
  493. depotName: "",
  494. taskId: "",
  495. keepSampleQuantity: "",
  496. };
  497. },
  498. closeDialog() {
  499. this.dialogVisible = false;
  500. this.isBatch = false;
  501. this.current = null;
  502. this.resetDisposeForm();
  503. },
  504. onDisposeConfirm(e) {
  505. const item = e.value[0];
  506. this.disposeForm.disposeType = item.value;
  507. this.showDisposePicker = false;
  508. this.disposeForm.sampleCondition = "";
  509. this.disposeForm.sampleDate = "";
  510. this.disposeForm.samplePlace = "";
  511. this.disposeForm.sampleRemark = "";
  512. this.disposeForm.producerManufacturer = "";
  513. this.disposeForm.depotId = "";
  514. this.disposeForm.depotName = "";
  515. this.disposeForm.taskId = "";
  516. if (item.value == 6 && this.current) {
  517. this.disposeForm.keepSampleQuantity =
  518. this.current.measureQuantity || "";
  519. }
  520. },
  521. onRefluxConfirm(e) {
  522. const item = e.value[0];
  523. this.disposeForm.taskId = item.taskId;
  524. this.showRefluxPicker = false;
  525. },
  526. onWarehouseConfirm(e) {
  527. const item = e.value[0];
  528. this.disposeForm.depotId = item.id;
  529. this.disposeForm.depotName = item.name;
  530. this.showWarehousePicker = false;
  531. },
  532. onDateConfirm(e) {
  533. const d = new Date(e.value);
  534. const year = d.getFullYear();
  535. const month = String(d.getMonth() + 1).padStart(2, "0");
  536. const day = String(d.getDate()).padStart(2, "0");
  537. this.disposeForm.sampleDate = `${year}-${month}-${day}`;
  538. this.showDatePicker = false;
  539. },
  540. async handleDispose() {
  541. if (!this.disposeForm.disposeType) {
  542. uni.showToast({ title: "请选择处置方式", icon: "none" });
  543. return;
  544. }
  545. const dt = this.disposeForm.disposeType;
  546. if ((dt == 3 || dt == 9) && !this.disposeForm.depotId) {
  547. uni.showToast({ title: "请选择入库仓库", icon: "none" });
  548. return;
  549. }
  550. if (dt == 6 && this.current) {
  551. const inputVal = Number(this.disposeForm.keepSampleQuantity);
  552. const maxVal = Number(this.current.measureQuantity);
  553. if (inputVal > maxVal) {
  554. uni.showToast({
  555. title: `留样数量不能超过${maxVal}`,
  556. icon: "none",
  557. });
  558. return;
  559. }
  560. }
  561. let params = {
  562. disposeType: this.disposeForm.disposeType,
  563. poList: [],
  564. refluxTask: null,
  565. };
  566. if (this.isBatch) {
  567. params.poList = this.selection.map((item) => {
  568. return { ...item, ...this.disposeForm };
  569. });
  570. } else {
  571. params.poList = [
  572. { ...JSON.parse(JSON.stringify(this.current)), ...this.disposeForm },
  573. ];
  574. }
  575. if (this.disposeForm.taskId) {
  576. params.refluxTask = this.refluxTaskList.find(
  577. (item) => item.taskId == this.disposeForm.taskId,
  578. );
  579. }
  580. try {
  581. await disposeApi(params);
  582. uni.showToast({ title: "处置成功", icon: "success" });
  583. this.closeDialog();
  584. this.loadData();
  585. } catch (e) {
  586. uni.showToast({ title: e || "处置失败", icon: "none" });
  587. }
  588. },
  589. confirmDelete(item) {
  590. uni.showModal({
  591. title: "提示",
  592. content: "确定要删除吗?",
  593. success: (res) => {
  594. if (res.confirm) {
  595. this.removeItem(item);
  596. }
  597. },
  598. });
  599. },
  600. async removeItem(item) {
  601. try {
  602. await deleteUnacceptedProductDetail([item.id]);
  603. uni.showToast({ title: "删除成功", icon: "success" });
  604. this.loadData();
  605. } catch (e) {
  606. uni.showToast({ title: e || "删除失败", icon: "none" });
  607. }
  608. },
  609. },
  610. };
  611. </script>
  612. <style lang="scss" scoped>
  613. .content-box {
  614. height: 100vh;
  615. overflow: hidden;
  616. display: flex;
  617. flex-direction: column;
  618. background-color: $page-bg;
  619. }
  620. .list_box {
  621. overflow: hidden;
  622. padding: 16rpx 0;
  623. padding-bottom: 120rpx;
  624. .u-list {
  625. height: 100% !important;
  626. }
  627. .card_box {
  628. width: 686rpx;
  629. margin: 0 auto 24rpx;
  630. background: #fff;
  631. border-radius: 18rpx;
  632. padding: 26rpx 30rpx;
  633. box-shadow: 0 6rpx 28rpx rgba(0, 0, 0, 0.06);
  634. box-sizing: border-box;
  635. .header {
  636. display: flex;
  637. align-items: center;
  638. margin-bottom: 18rpx;
  639. .round {
  640. width: 40rpx;
  641. height: 40rpx;
  642. line-height: 40rpx;
  643. border-radius: 50%;
  644. background: $theme-color;
  645. color: #fff;
  646. text-align: center;
  647. font-size: 22rpx;
  648. }
  649. .checkbox-wrap {
  650. margin-right: 12rpx;
  651. display: flex;
  652. align-items: center;
  653. }
  654. .orderId {
  655. margin-left: 14rpx;
  656. font-size: 28rpx;
  657. font-weight: 600;
  658. color: #333;
  659. flex: 1;
  660. }
  661. .status-tag {
  662. font-size: 22rpx;
  663. padding: 6rpx 18rpx;
  664. border-radius: 32rpx;
  665. font-weight: 500;
  666. }
  667. .status-0 {
  668. background: #fff3e0;
  669. color: #e67e22;
  670. }
  671. .status-1 {
  672. background: #eaf3ff;
  673. color: #2a68ff;
  674. }
  675. .status-2 {
  676. background: #e8f6ec;
  677. color: #157a2c;
  678. }
  679. }
  680. .row {
  681. display: flex;
  682. justify-content: space-between;
  683. margin-bottom: 12rpx;
  684. font-size: 26rpx;
  685. color: #333;
  686. .label {
  687. color: #888;
  688. min-width: 160rpx;
  689. font-weight: 400;
  690. }
  691. .value {
  692. flex: 1;
  693. font-weight: 500;
  694. text-align: right;
  695. word-break: break-all;
  696. }
  697. }
  698. .btn-row {
  699. display: flex;
  700. justify-content: flex-end;
  701. gap: 20rpx;
  702. margin-top: 20rpx;
  703. padding-top: 20rpx;
  704. border-top: 1rpx solid #f0f0f0;
  705. button {
  706. font-size: 26rpx;
  707. padding: 10rpx 36rpx;
  708. border-radius: 32rpx;
  709. line-height: 1.6;
  710. margin: 0;
  711. }
  712. .btn-dispose {
  713. background: $theme-color;
  714. color: #fff;
  715. }
  716. .btn-delete {
  717. background: #fff;
  718. color: #e74c3c;
  719. border: 1rpx solid #e74c3c;
  720. }
  721. }
  722. }
  723. }
  724. .footer-bar {
  725. position: fixed;
  726. bottom: 0;
  727. left: 0;
  728. width: 100%;
  729. padding: 20rpx 32rpx;
  730. padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
  731. background: #fff;
  732. box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.06);
  733. z-index: 100;
  734. box-sizing: border-box;
  735. display: flex;
  736. align-items: center;
  737. gap: 24rpx;
  738. .footer-left {
  739. display: flex;
  740. align-items: center;
  741. gap: 8rpx;
  742. .select-all-text {
  743. font-size: 28rpx;
  744. color: #333;
  745. }
  746. }
  747. .btn-batch {
  748. flex: 1;
  749. height: 80rpx;
  750. line-height: 80rpx;
  751. background: $theme-color;
  752. color: #fff;
  753. font-size: 30rpx;
  754. border-radius: 40rpx;
  755. margin: 0;
  756. &[disabled] {
  757. opacity: 0.5;
  758. }
  759. }
  760. }
  761. .popup-content {
  762. padding: 32rpx;
  763. max-height: 80vh;
  764. overflow-y: auto;
  765. .popup-header {
  766. display: flex;
  767. justify-content: space-between;
  768. align-items: center;
  769. margin-bottom: 32rpx;
  770. .popup-title {
  771. font-size: 34rpx;
  772. font-weight: 600;
  773. color: #333;
  774. }
  775. .popup-close {
  776. font-size: 36rpx;
  777. color: #999;
  778. padding: 10rpx;
  779. }
  780. }
  781. .form-item {
  782. margin-bottom: 28rpx;
  783. .form-label {
  784. font-size: 28rpx;
  785. color: #333;
  786. margin-bottom: 12rpx;
  787. font-weight: 500;
  788. &.required::before {
  789. content: "*";
  790. color: #e74c3c;
  791. margin-right: 6rpx;
  792. }
  793. }
  794. .picker-box {
  795. display: flex;
  796. align-items: center;
  797. justify-content: space-between;
  798. height: 80rpx;
  799. padding: 0 24rpx;
  800. background: #f8f8f8;
  801. border-radius: 12rpx;
  802. font-size: 28rpx;
  803. color: #333;
  804. .placeholder {
  805. color: #bbb;
  806. }
  807. .arrow {
  808. color: #ccc;
  809. font-size: 28rpx;
  810. }
  811. }
  812. .input-box {
  813. display: flex;
  814. align-items: center;
  815. background: #f8f8f8;
  816. border-radius: 12rpx;
  817. padding: 0 24rpx;
  818. min-height: 80rpx;
  819. input {
  820. flex: 1;
  821. height: 80rpx;
  822. font-size: 28rpx;
  823. color: #333;
  824. }
  825. textarea {
  826. flex: 1;
  827. font-size: 28rpx;
  828. color: #333;
  829. padding: 20rpx 0;
  830. min-height: 80rpx;
  831. }
  832. .unit {
  833. color: #888;
  834. font-size: 26rpx;
  835. margin-left: 12rpx;
  836. }
  837. }
  838. }
  839. .popup-footer {
  840. display: flex;
  841. gap: 24rpx;
  842. margin-top: 40rpx;
  843. padding-bottom: env(safe-area-inset-bottom);
  844. button {
  845. flex: 1;
  846. height: 80rpx;
  847. line-height: 80rpx;
  848. font-size: 30rpx;
  849. border-radius: 40rpx;
  850. margin: 0;
  851. }
  852. .btn-cancel {
  853. background: #f5f5f5;
  854. color: #666;
  855. }
  856. .btn-confirm {
  857. background: $theme-color;
  858. color: #fff;
  859. }
  860. }
  861. }
  862. </style>