index.vue 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679
  1. <template>
  2. <view class="receipt-form-page">
  3. <u-navbar placeholder :autoBack="true" :title="pageTitle" @rightClick="submitForm">
  4. <view class="u-nav-slot" slot="right"> 保存 </view>
  5. </u-navbar>
  6. <!-- 表单内容 -->
  7. <view class="follow_form_wrap">
  8. <u--form labelPosition="left" labelWidth="100" :model="form" :rules="rules" ref="receiptFormRef" class="form_wrap"
  9. :errorType="'toast'">
  10. <u-form-item label="最后修改时间" prop="updateTime" borderBottom>
  11. <u--input v-model="form.updateTime" placeholder="最后修改时间" disabled></u--input>
  12. </u-form-item>
  13. <u-form-item label="订单类型" prop="customerServiceName" borderBottom>
  14. <ld-select :list="sendOrderTypeDict" label-key="dictLabel" value-key="dictValue" placeholder="请选择类别"
  15. v-model="form.customerServiceName" :border="false"></ld-select>
  16. <u-icon slot="right" name="arrow-right"></u-icon>
  17. </u-form-item>
  18. <u-form-item label="物品名称" prop="item" borderBottom class="form_required">
  19. <u--input v-model="form.item" placeholder="请输入物品名称" border="none" :disabled="!isEdit"></u--input>
  20. </u-form-item>
  21. <u-form-item label="类别" prop="category" borderBottom class="form_required">
  22. <ld-select :list="categoryDict" label-key="dictLabel" value-key="dictValue" placeholder="请选择类别"
  23. v-model="form.category" :border="false"></ld-select>
  24. <u-icon slot="right" name="arrow-right"></u-icon>
  25. </u-form-item>
  26. <u-form-item label="品牌" prop="brand" borderBottom>
  27. <ld-select :list="brandDict" label-key="dictLabel" value-key="dictValue" placeholder="请选择品牌"
  28. v-model="form.brand" :border="false"></ld-select>
  29. <u-icon slot="right" name="arrow-right"></u-icon>
  30. </u-form-item>
  31. <u-form-item label="是否需要查码" prop="needCheckCode" borderBottom class="form_required">
  32. <u-radio-group v-model="form.needCheckCode" :disabled="!isEdit" @change="(val) => (form.needCheckCode = val)">
  33. <u-radio v-for="item in needCheckCodeOptions" :key="item.value" :name="item.value" :label="item.label"
  34. style="margin-right: 10px"></u-radio>
  35. </u-radio-group>
  36. </u-form-item>
  37. <u-form-item label="编码" prop="code" borderBottom>
  38. <u--input v-model="form.code" :disabled="form.needCheckCode !== 1 || !isEdit" placeholder="请输入编码"></u--input>
  39. </u-form-item>
  40. <u-form-item label="查码费" prop="checkCodeFee" borderBottom>
  41. <u--input v-model.number="form.checkCodeFee" type="number" placeholder="请输入查码费" border="none"
  42. :disabled="!isEdit"></u--input>
  43. </u-form-item>
  44. <u-form-item label="表款" prop="tableFee" borderBottom>
  45. <u--input v-model.number="form.tableFee" type="number" placeholder="请输入表款" border="none"
  46. :disabled="!isEdit"></u--input>
  47. </u-form-item>
  48. <u-form-item label="好处费" prop="benefitFee" borderBottom>
  49. <u--input v-model.number="form.benefitFee" type="number" placeholder="请输入好处费" border="none"
  50. :disabled="!isEdit"></u--input>
  51. </u-form-item>
  52. <u-form-item label="运费" prop="freight" borderBottom>
  53. <u--input v-model.number="form.freight" type="number" placeholder="请输入运费" border="none"
  54. :disabled="!isEdit"></u--input>
  55. </u-form-item>
  56. <u-form-item label="维修金额" prop="repairAmount" borderBottom>
  57. <u--input v-model.number="form.repairAmount" type="number" placeholder="请输入维修金额" border="none"
  58. :disabled="!isEdit"></u--input>
  59. </u-form-item>
  60. <u-form-item label="成本合计" prop="totalCost" borderBottom>
  61. <u--input v-model.number="form.totalCost" type="number" placeholder="自动计算成本合计" disabled></u--input>
  62. </u-form-item>
  63. <u-form-item label="卖价" prop="sellingPrice" borderBottom>
  64. <u--input v-model.number="form.sellingPrice" type="number" placeholder="请输入卖价" border="none"
  65. :disabled="!isEdit"></u--input>
  66. </u-form-item>
  67. <u-form-item label="业绩" prop="performance" borderBottom>
  68. <u--input v-model.number="form.performance" type="number" placeholder="自动计算业绩" disabled></u--input>
  69. </u-form-item>
  70. <u-form-item label="分单比例" prop="splitRatio" borderBottom>
  71. <u--input v-model="form.splitRatio" type="number" step="0.01" placeholder="0-100" :disabled="!isEdit"
  72. @blur="validateSplitRatio"></u--input>
  73. </u-form-item>
  74. <u-form-item label="毛业绩" prop="grossPerformance" borderBottom>
  75. <u--input v-model.number="form.grossPerformance" type="number" :placeholder="canEditGrossPerformance ? '请输入毛业绩' : '自动计算毛业绩'
  76. " :disabled="!canEditGrossPerformance"></u--input>
  77. </u-form-item>
  78. <u-form-item label="开户人姓名" prop="customName" borderBottom>
  79. <u--input v-model="form.customName" placeholder="请输入开户人姓名" border="none" :disabled="!isEdit"></u--input>
  80. </u-form-item>
  81. <u-form-item label="身份证号码" prop="idCard" borderBottom>
  82. <u--input v-model="form.idCard" placeholder="请输入客户身份证号码" border="none" :disabled="!isEdit"></u--input>
  83. </u-form-item>
  84. <u-form-item label="银行卡号" prop="bankCardNumber" borderBottom>
  85. <u--input v-model="form.bankCardNumber" placeholder="请输入银行卡号" border="none" :disabled="!isEdit"></u--input>
  86. </u-form-item>
  87. <u-form-item label="银行名称" prop="bankName" borderBottom>
  88. <u--input v-model="form.bankName" placeholder="请输入银行名称" border="none" :disabled="!isEdit"></u--input>
  89. </u-form-item>
  90. <u-form-item label="快递单号" prop="expressOrderNo" borderBottom>
  91. <u--input v-model="form.expressOrderNo" placeholder="请输入快递单号" border="none" :disabled="!isEdit"></u--input>
  92. </u-form-item>
  93. <u-form-item label="附件" prop="fileIds" borderBottom>
  94. <view class="file-list">
  95. <view v-for="file in fileOptions" :key="file.id" class="file-item" @click="handleFileSelect(file)" :class="{
  96. fileSelected: fileIds.includes(file.id.toString()),
  97. fileDisabled:
  98. file.receiptFormId !== null && file.receiptFormId !== form.id,
  99. }" :disabled="file.receiptFormId !== null && file.receiptFormId !== form.id
  100. ">
  101. <view class="file-info">
  102. <text class="file-name">{{ handleShowLabel(file) }}</text>
  103. <text v-if="
  104. file.receiptFormId !== null &&
  105. file.receiptFormId !== form.id
  106. " class="file-bound">已绑定</text>
  107. </view>
  108. <u-icon v-if="fileIds.includes(file.id.toString())" name="checkmark" color="#409eff" size="18"
  109. class="fileSelectedIcon"></u-icon>
  110. </view>
  111. </view>
  112. <view v-if="fileOptions.length === 0" class="no-files">
  113. <u-empty mode="data" text="暂无附件"></u-empty>
  114. </view>
  115. </u-form-item>
  116. <u-form-item label="收单备注" prop="receiptRemark" borderBottom>
  117. <u-textarea confirmType="done" v-model="form.receiptRemark" placeholder="请输入收单备注" :disabled="!isEdit"
  118. auto-height></u-textarea>
  119. </u-form-item>
  120. </u--form>
  121. </view>
  122. </view>
  123. </template>
  124. <script>
  125. import { cloneDeep } from "lodash";
  126. import ldSelect from "@/components/ld-select/ld-select.vue";
  127. export default {
  128. name: "ReceiptForm",
  129. components: {
  130. ldSelect,
  131. },
  132. data() {
  133. return {
  134. loading: false,
  135. form: {
  136. id: undefined,
  137. sendFormId: '',
  138. clueId: '',
  139. item: '',
  140. brand: '',
  141. needCheckCode: 1,
  142. code: '',
  143. tableFee: 0,
  144. benefitFee: 0,
  145. freight: 0,
  146. checkCodeFee: 0,
  147. totalCost: 0,
  148. sellingPrice: 0,
  149. performance: 0,
  150. receiptRemark: '',
  151. repairAmount: 0,
  152. grossPerformance: 0,
  153. expressOrderNo: '',
  154. fileIds: '',
  155. category: '',
  156. customName: '',
  157. idCard: '',
  158. bankCardNumber: '',
  159. bankName: '',
  160. customerServiceName: '',
  161. updateTime: '',
  162. splitRatio: 0
  163. },
  164. fileOptions: [],
  165. orderId: "",
  166. clueId: "",
  167. receiptId: "",
  168. receiptDetail: {},
  169. needCheckCodeOptions: [
  170. { label: "是", value: 1 },
  171. { label: "否", value: 2 },
  172. ],
  173. categoryDict: [],
  174. sendOrderTypeDict: [],
  175. brandDict: [],
  176. labelStyle: {
  177. fontSize: "28rpx",
  178. color: "#606266",
  179. },
  180. // 表单验证规则
  181. rules: {
  182. item: [{ required: true, message: "请输入物品名称", trigger: "blur" }],
  183. category: [
  184. { required: true, message: "请选择类别", trigger: "change" },
  185. ],
  186. needCheckCode: [
  187. {
  188. validator: (rule, value, callback) => {
  189. if (!value) {
  190. callback(new Error("请选择是否查码"));
  191. } else {
  192. callback();
  193. }
  194. },
  195. trigger: "blur",
  196. },
  197. ],
  198. brand: [
  199. {
  200. required: true,
  201. message: "请选择品牌",
  202. trigger: ["blur", "change"]
  203. }
  204. ],
  205. code: [
  206. {
  207. validator: (rule, value, callback) => {
  208. if (this.form.needCheckCode === 1 && !value) {
  209. callback(new Error("编码不能为空"));
  210. } else {
  211. callback();
  212. }
  213. },
  214. trigger: "blur",
  215. },
  216. ],
  217. },
  218. };
  219. },
  220. computed: {
  221. pageTitle() {
  222. return this.form.id ? "编辑收单" : "新增收单";
  223. },
  224. fileIds: {
  225. get() {
  226. if (this.form.fileIds) {
  227. return this.form.fileIds.split(",").filter((id) => id);
  228. } else {
  229. return [];
  230. }
  231. },
  232. set(value) {
  233. this.form.fileIds = value.join(",");
  234. },
  235. },
  236. isEdit() {
  237. return true;
  238. },
  239. // 判断是否显示保存按钮:status=2时,只有接单人本人可以编辑
  240. canShowSaveButton() {
  241. if (!this.receiptDetail.status) return true;
  242. const { status, identification } = this.receiptDetail;
  243. const currentUserId = this.$store.state.user.userId;
  244. // 如果status不是"2",显示保存按钮
  245. if (status !== "2") {
  246. return true;
  247. }
  248. // 如果status是"2",只有接单人本人可以看到保存按钮
  249. return String(identification) === String(currentUserId);
  250. },
  251. // 自动计算成本合计 = 表款 + 好处费 + 运费 + 查码费 + 维修金额
  252. calculatedTotalCost() {
  253. const { tableFee, benefitFee, freight, checkCodeFee, repairAmount } =
  254. this.form;
  255. return (
  256. (tableFee || 0) +
  257. (benefitFee || 0) +
  258. (freight || 0) +
  259. (checkCodeFee || 0) +
  260. (repairAmount || 0)
  261. );
  262. },
  263. // 自动计算业绩 = 卖价 - 成本合计
  264. // 卖价为空时不计算,避免出现负数业绩
  265. calculatedPerformance() {
  266. const { sellingPrice } = this.form;
  267. // 卖价为空或为0时,不计算业绩
  268. if (!sellingPrice || sellingPrice <= 0) {
  269. return null;
  270. }
  271. return sellingPrice - this.calculatedTotalCost;
  272. },
  273. // 自动计算毛业绩 = 业绩 × 分单比例(仅当两者都不为空时)
  274. // 智能判断:<=1直接乘,>1先除以100再乘
  275. // 四舍五入保留两位小数
  276. calculatedGrossPerformance() {
  277. const { splitRatio } = this.form;
  278. if (
  279. this.calculatedPerformance &&
  280. splitRatio !== null &&
  281. splitRatio !== undefined &&
  282. splitRatio !== ""
  283. ) {
  284. // 智能判断:<=1直接乘,>1先除以100再乘
  285. const ratio = splitRatio <= 1 ? splitRatio : splitRatio / 100;
  286. const result = this.calculatedPerformance * ratio;
  287. // 四舍五入保留两位小数
  288. return Math.round(result * 100) / 100;
  289. }
  290. return null;
  291. },
  292. // 毛业绩是否可编辑:业绩不为空 且 比例为空
  293. canEditGrossPerformance() {
  294. return (
  295. this.calculatedPerformance &&
  296. !this.form.splitRatio &&
  297. this.form.splitRatio !== 0 &&
  298. this.isEdit
  299. );
  300. },
  301. },
  302. watch: {
  303. // 监听成本合计变化,自动更新form
  304. calculatedTotalCost(val) {
  305. this.form.totalCost = val;
  306. },
  307. // 监听业绩业绩变化,自动更新form
  308. calculatedPerformance(val) {
  309. this.form.performance = val;
  310. },
  311. // 监听毛业绩变化,仅当比例不为空时自动更新form
  312. calculatedGrossPerformance(val) {
  313. if (
  314. this.form.splitRatio !== null &&
  315. this.form.splitRatio !== undefined &&
  316. this.form.splitRatio !== "" &&
  317. val !== null
  318. ) {
  319. this.form.grossPerformance = val;
  320. }
  321. },
  322. },
  323. onLoad(options) {
  324. // 从路由参数获取orderId和clueId
  325. this.orderId = options.orderId;
  326. this.clueId = options.clueId;
  327. this.receiptId = options.receiptId;
  328. this.getDicts().then(() => {
  329. this.initForm();
  330. });
  331. },
  332. methods: {
  333. // 获取字典数据
  334. async getDicts() {
  335. try {
  336. const [categoryRes, brandRes, sendOrderTypeRes] = await Promise.all([
  337. this.$getDicts("crm_form_category"),
  338. this.$getDicts("crm_form_brand"),
  339. this.$getDicts("crm_sendOrder_type")
  340. ]);
  341. this.categoryDict = categoryRes;
  342. this.brandDict = brandRes;
  343. this.sendOrderTypeDict = sendOrderTypeRes;
  344. } catch (error) {
  345. console.error("获取字典数据失败:", error);
  346. }
  347. },
  348. handleBack() {
  349. uni.navigateBack();
  350. },
  351. /** 表单重置 */
  352. reset() {
  353. const form = Object.assign({
  354. id: undefined,
  355. sendFormId: this.orderId,
  356. clueId: this.clueId,
  357. item: undefined,
  358. brand: undefined,
  359. needCheckCode: 1,
  360. code: undefined,
  361. tableFee: undefined,
  362. benefitFee: undefined,
  363. freight: undefined,
  364. checkCodeFee: undefined,
  365. totalCost: undefined,
  366. sellingPrice: undefined,
  367. performance: undefined,
  368. receiptRemark: undefined,
  369. repairAmount: undefined,
  370. grossPerformance: undefined,
  371. expressOrderNo: undefined,
  372. fileIds: "",
  373. category: undefined,
  374. customName: undefined,
  375. idCard: undefined,
  376. bankCardNumber: undefined,
  377. bankName: undefined,
  378. customerServiceName: undefined,
  379. updateTime: undefined,
  380. splitRatio: undefined,
  381. });
  382. // 从订单详情预填充字段
  383. if (this.receiptDetail) {
  384. form.status = this.receiptDetail.status;
  385. form.identification = this.receiptDetail.identification;
  386. form.item = this.receiptDetail.item;
  387. form.category = this.receiptDetail.category;
  388. form.brand = this.receiptDetail.brand;
  389. }
  390. this.form = form;
  391. },
  392. handleShowLabel(file) {
  393. // 获取文件在fileIds数组中的索引,如果存在则显示序号
  394. const index = this.fileIds.indexOf(file.id.toString());
  395. let label = "";
  396. if (index !== -1) {
  397. label = `[${index + 1}] `;
  398. }
  399. label += file.fileName;
  400. if (file.remark) {
  401. label += `(${file.remark})`;
  402. }
  403. // 如果文件已绑定到其他收单,显示绑定信息
  404. if (file.receiptFormId !== null && file.receiptFormId !== this.form.id) {
  405. label += ` - 已绑定${file.item || ""}`;
  406. }
  407. return label;
  408. },
  409. initForm() {
  410. // 获取订单详情数据
  411. uni.$u.api
  412. .getClueSendFormVoByOrderId({
  413. id: this.orderId,
  414. })
  415. .then((res) => {
  416. this.receiptDetail = res.data;
  417. // 如果有receiptId,说明是编辑模式,获取收单详情
  418. if (this.receiptId) {
  419. return uni.$u.api
  420. .getReceiptForm(this.receiptId)
  421. .then((receiptRes) => {
  422. this.form = receiptRes.data;
  423. // 在数据初始化完成后获取附件列表
  424. this.fetchFileOptions();
  425. });
  426. } else {
  427. // 新增模式:初始化表单数据(需要receiptDetail数据才能预填充字段)
  428. this.reset();
  429. // 在数据初始化完成后获取附件列表
  430. this.fetchFileOptions();
  431. }
  432. })
  433. .catch((error) => {
  434. console.error("初始化表单失败:", error);
  435. uni.$u.toast("初始化表单失败");
  436. });
  437. },
  438. // 获取附件选项列表
  439. async fetchFileOptions() {
  440. try {
  441. const params = {
  442. clueId: this.receiptDetail.clueId,
  443. sourceId: this.receiptDetail.id,
  444. notBound: "1",
  445. orderFileType: "3",
  446. type: "2",
  447. };
  448. const { rows } = await uni.$u.api.selectClueFileByDto(params);
  449. this.fileOptions = rows || [];
  450. } catch (error) {
  451. console.error("获取附件列表失败:", error);
  452. uni.$u.toast("获取附件列表失败");
  453. }
  454. },
  455. // 文件选择
  456. handleFileSelect(file) {
  457. if (!this.isEdit) return;
  458. // 如果文件已经被绑定到其他收单,不允许选择
  459. if (file.receiptFormId !== null && file.receiptFormId !== this.form.id) {
  460. return;
  461. }
  462. const fileId = file.id.toString();
  463. const index = this.fileIds.indexOf(fileId);
  464. const newFileIds = [...this.fileIds]; // 创建数组副本
  465. if (index > -1) {
  466. // 已选中,取消选择
  467. newFileIds.splice(index, 1);
  468. } else {
  469. // 未选中,添加选择
  470. newFileIds.push(fileId);
  471. }
  472. // 重新赋值,触发set方法
  473. this.fileIds = newFileIds;
  474. },
  475. // 分单比例验证:非空时范围必须在0-100之间
  476. validateSplitRatio() {
  477. const { splitRatio } = this.form;
  478. if (
  479. splitRatio === null ||
  480. splitRatio === undefined ||
  481. splitRatio === ""
  482. ) {
  483. return; // 允许为空
  484. }
  485. const ratio = Number(splitRatio);
  486. // 范围验证:0-100
  487. if (ratio < 0) {
  488. uni.$u.toast("分单比例不能小于0");
  489. this.form.splitRatio = 0;
  490. } else if (ratio > 100) {
  491. uni.$u.toast("分单比例不能大于100");
  492. this.form.splitRatio = 100;
  493. }
  494. },
  495. // 提交表单
  496. submitForm() {
  497. this.$refs.receiptFormRef.validate().then(async (valid) => {
  498. if (valid) {
  499. await this.handleUpdate();
  500. } else {
  501. uni.$u.toast("请检查表单填写是否正确");
  502. }
  503. });
  504. },
  505. // 更新表单
  506. async handleUpdate() {
  507. try {
  508. this.loading = true;
  509. // 准备提交数据
  510. const submitData = {
  511. ...this.form,
  512. sendFormId: this.orderId,
  513. clueId: this.clueId,
  514. };
  515. // 根据是否有id判断是新增还是修改
  516. if (this.form.id) {
  517. // 修改
  518. await uni.$u.api.updateReceiptForm(submitData);
  519. uni.$emit('addReceiptFormSuccess');
  520. uni.$u.toast("修改成功");
  521. } else {
  522. // 新增
  523. await uni.$u.api.addReceiptForm(submitData);
  524. uni.$emit('addReceiptFormSuccess');
  525. uni.$u.toast("新增成功");
  526. }
  527. // 延迟返回上一页
  528. setTimeout(() => {
  529. uni.navigateBack();
  530. }, 1500);
  531. } catch (error) {
  532. console.error("保存失败:", error);
  533. uni.$u.toast("保存失败,请重试");
  534. } finally {
  535. this.loading = false;
  536. }
  537. },
  538. },
  539. };
  540. </script>
  541. <style lang="scss">
  542. .receipt-form-page {
  543. background-color: #fff;
  544. }
  545. @import "@/static/follow/index.scss";
  546. // 附件列表样式优化
  547. .file-list {
  548. display: flex;
  549. flex-direction: column;
  550. gap: 16rpx;
  551. padding: 10rpx 0;
  552. }
  553. .file-item {
  554. display: flex;
  555. align-items: center;
  556. justify-content: space-between;
  557. padding: 24rpx 30rpx;
  558. background-color: #f8f9fa;
  559. border-radius: 12rpx;
  560. border: 2rpx solid transparent;
  561. transition: all 0.3s ease;
  562. position: relative;
  563. cursor: pointer;
  564. &:active {
  565. background-color: #e9ecef;
  566. transform: scale(0.98);
  567. }
  568. // 选中状态样式
  569. &.fileSelected {
  570. background-color: #e6f4ff;
  571. border-color: #409eff;
  572. box-shadow: 0 4rpx 12rpx rgba(64, 158, 255, 0.2);
  573. }
  574. // 禁用状态样式
  575. &.fileDisabled {
  576. background-color: #f5f5f5;
  577. opacity: 0.6;
  578. cursor: not-allowed;
  579. &:active {
  580. transform: none;
  581. background-color: #f5f5f5;
  582. }
  583. }
  584. .file-info {
  585. flex: 1;
  586. display: flex;
  587. align-items: center;
  588. gap: 16rpx;
  589. .file-name {
  590. font-size: 28rpx;
  591. color: #303133;
  592. line-height: 40rpx;
  593. word-break: break-all;
  594. }
  595. .file-bound {
  596. font-size: 24rpx;
  597. color: #909399;
  598. background-color: #f5f7fa;
  599. padding: 2rpx 16rpx;
  600. border-radius: 16rpx;
  601. }
  602. }
  603. .u-icon {
  604. // 为选中图标添加动画效果
  605. &.fileSelectedIcon {
  606. animation: fadeInScale 0.3s ease;
  607. }
  608. }
  609. }
  610. // 动画效果
  611. @keyframes fadeInScale {
  612. 0% {
  613. opacity: 0;
  614. transform: scale(0.5);
  615. }
  616. 100% {
  617. opacity: 1;
  618. transform: scale(1);
  619. }
  620. }
  621. // 无附件时的样式
  622. .no-files {
  623. padding: 60rpx 0;
  624. text-align: center;
  625. }
  626. </style>