index.vue 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780
  1. <template>
  2. <div class="user">
  3. <div class="tree">
  4. <treeList title="产品分类" submitType="1" :data="treeListData" v-model="sourceList.pagination.productClassifyId" @change="treeChange"
  5. @changeTreeList="getTreeList">
  6. </treeList>
  7. </div>
  8. <div class="content">
  9. <byTable :source="sourceList.data" :pagination="sourceList.pagination" :config="config" :loading="loading" highlight-current-row
  10. :selectConfig="selectConfig" :table-events="{
  11. //element talbe事件都能传
  12. select: select,
  13. }" :action-list="[
  14. props.selectStatus
  15. ? {}
  16. : {
  17. text: 'Excel导入',
  18. action: () => openExcel(),
  19. disabled: false,
  20. },
  21. props.selectStatus
  22. ? {}
  23. : {
  24. text: '添加',
  25. action: () => openModal('add'),
  26. disabled: false,
  27. },
  28. ]" @get-list="getList">
  29. <template #name="{ item }">
  30. <div>
  31. <span style="color: #409eff; cursor: pointer; word-break: break-all" @click="handleOpenProductContract(item)">{{ item.name }}</span>
  32. </div>
  33. </template>
  34. <template #pic="{ item }">
  35. <div v-if="item.fileList.length > 0">
  36. <img :src="item.fileList[0].fileUrl" class="pic" @click="handleClickFile(item.fileList[0])" />
  37. </div>
  38. <div v-else></div>
  39. </template>
  40. <template #size="{ item }">
  41. <div>
  42. <span>{{ item.productLong }}cm</span>*
  43. <span>{{ item.productWide }}cm</span>*
  44. <span>{{ item.productHigh }}cm</span>
  45. </div>
  46. </template>
  47. <template #price="{ item }">
  48. <div>
  49. <span v-if="item.price">{{ item.currency }} {{ item.price }}</span>
  50. </div>
  51. </template>
  52. <template #costPrice="{ item }">
  53. <div>
  54. <span v-if="item.costPrice">{{ item.costCurrency }} {{ item.costPrice }}</span>
  55. </div>
  56. </template>
  57. </byTable>
  58. </div>
  59. <el-dialog :title="modalType == 'add' ? '添加产品' : '编辑产品'" v-model="dialogVisible" width="700" v-loading="submitLoading" destroy-on-close>
  60. <div class="public_height_dialog">
  61. <byForm :formConfig="formConfig" :formOption="formOption" v-model="formData.data" :rules="rules" ref="byform">
  62. <template #nameEnglish>
  63. <div style="width: 100%">
  64. <el-form-item label="英文名" prop="nameEnglish">
  65. <el-input v-model="formData.data.nameEnglish" placeholder="请输入" onkeyup="value=value.replace(/[^\x00-\xff]/g, '')"></el-input>
  66. <!-- @input="(val) => handleKeyup(val)" -->
  67. </el-form-item>
  68. </div>
  69. </template>
  70. <template #productPic>
  71. <div>
  72. <el-upload v-model:fileList="fileList" :action="uploadUrl" :data="uploadData" list-type="picture-card" :on-remove="handleRemove"
  73. :before-upload="handleBeforeUpload" :on-preview="handlePreview" accept=".gif, .jpeg, .jpg, .png">
  74. <el-icon>
  75. <Plus />
  76. </el-icon>
  77. </el-upload>
  78. </div>
  79. </template>
  80. </byForm>
  81. </div>
  82. <template #footer>
  83. <el-button @click="dialogVisible = false" size="large">取 消</el-button>
  84. <el-button type="primary" @click="submitForm('byform')" size="large" :loading="submitLoading">确 定</el-button>
  85. </template>
  86. </el-dialog>
  87. <el-dialog title="导入产品" v-model="openExcelDialog" width="400" v-loading="excelLoading">
  88. <el-upload :action="actionUrl + '/productInfo/excelImportByEhsd'" :headers="headers" :on-success="handleSuccess" :on-progress="handleProgress"
  89. :show-file-list="false" :on-error="handleError" accept=".xlsx">
  90. <el-button type="primary">点击导入</el-button>
  91. </el-upload>
  92. <template #footer>
  93. <el-button @click="openExcelDialog = false" size="large">取 消</el-button>
  94. </template>
  95. </el-dialog>
  96. <el-dialog v-if="productContractDialog" v-model="productContractDialog" :title="'外销合同'" width="80%" append-to-body>
  97. <ProductContract :currentProductId="currentProductId"></ProductContract>
  98. </el-dialog>
  99. </div>
  100. </template>
  101. <script setup>
  102. import { ElMessage, ElMessageBox } from "element-plus";
  103. import byTable from "@/components/byTable/index";
  104. import byForm from "@/components/byForm/index";
  105. import treeList from "@/components/product/treeList";
  106. import { getToken } from "@/utils/auth";
  107. import ProductContract from "@/components/contractCom/productContract.vue";
  108. const headers = ref({ Authorization: "Bearer " + getToken() });
  109. const actionUrl = import.meta.env.VITE_APP_BASE_API;
  110. const loading = ref(false);
  111. const submitLoading = ref(false);
  112. const treeListData = ref([]);
  113. const innerMethon = ref([]);
  114. const outsideMethon = ref([]);
  115. const productUnit = ref([]);
  116. const accountCurrency = ref([]);
  117. const sourceList = ref({
  118. data: [],
  119. pagination: {
  120. total: 3,
  121. pageNum: 1,
  122. pageSize: 10,
  123. type: "",
  124. productClassifyId: "",
  125. keyword: "",
  126. definition: "1",
  127. },
  128. });
  129. let dialogVisible = ref(false);
  130. let openExcelDialog = ref(false);
  131. let excelLoading = ref(false);
  132. let modalType = ref("add");
  133. let rules = ref({
  134. productClassifyId: [
  135. { required: true, message: "请选择产品分类", trigger: "change" },
  136. ],
  137. name: [{ required: true, message: "请输入产品名称", trigger: "blur" }],
  138. nameEnglish: [
  139. { required: true, message: "请输入产品英文名", trigger: "blur" },
  140. ],
  141. productLong: [
  142. { required: true, message: "请输入长 (cm)", trigger: "blur" },
  143. ],
  144. productWide: [
  145. { required: true, message: "请输入宽 (cm)", trigger: "blur" },
  146. ],
  147. productHigh: [
  148. { required: true, message: "请输入高 (cm)", trigger: "blur" },
  149. ],
  150. innerPackMethod: [
  151. { required: true, message: "请选择内包装方式", trigger: "change" },
  152. ],
  153. outerPackMethod: [
  154. { required: true, message: "请选择外包装方式", trigger: "change" },
  155. ],
  156. });
  157. const { proxy } = getCurrentInstance();
  158. const props = defineProps({
  159. selectStatus: Boolean,
  160. });
  161. const selectConfig = reactive([
  162. // {
  163. // label: "产品类型",
  164. // prop: "type",
  165. // data: [],
  166. // },
  167. ]);
  168. const config = computed(() => {
  169. return [
  170. {
  171. attrs: {
  172. label: "图片",
  173. slot: "pic",
  174. align: "center",
  175. width: 100,
  176. },
  177. },
  178. {
  179. attrs: {
  180. label: "产品编码",
  181. prop: "code",
  182. },
  183. },
  184. {
  185. attrs: {
  186. label: "产品名称",
  187. slot: "name",
  188. },
  189. },
  190. {
  191. attrs: {
  192. label: "尺寸",
  193. slot: "size",
  194. },
  195. },
  196. {
  197. attrs: {
  198. label: "销售指导价",
  199. slot: "price",
  200. width: 150,
  201. },
  202. },
  203. {
  204. attrs: {
  205. label: "成本价",
  206. slot: "costPrice",
  207. width: 150,
  208. },
  209. },
  210. {
  211. attrs: {
  212. label: "操作",
  213. width: "120",
  214. align: "center",
  215. },
  216. // 渲染 el-button,一般用在最后一列。
  217. renderHTML(row) {
  218. return [
  219. props.selectStatus
  220. ? {
  221. attrs: {
  222. label: "选择",
  223. type: "primary",
  224. text: true,
  225. },
  226. el: "button",
  227. click() {
  228. clickSelect(row);
  229. },
  230. }
  231. : {
  232. attrs: {
  233. label: "修改",
  234. type: "primary",
  235. text: true,
  236. },
  237. el: "button",
  238. click() {
  239. getDtl(row);
  240. },
  241. },
  242. props.selectStatus
  243. ? {}
  244. : {
  245. attrs: {
  246. label: "删除",
  247. type: "danger",
  248. text: true,
  249. },
  250. el: "button",
  251. click() {
  252. // 弹窗提示是否删除
  253. ElMessageBox.confirm(
  254. "此操作将永久删除该数据, 是否继续?",
  255. "提示",
  256. {
  257. confirmButtonText: "确定",
  258. cancelButtonText: "取消",
  259. type: "warning",
  260. }
  261. ).then(() => {
  262. // 删除
  263. proxy
  264. .post("/productInfo/delete", {
  265. id: row.id,
  266. })
  267. .then((res) => {
  268. ElMessage({
  269. message: "删除成功",
  270. type: "success",
  271. });
  272. getList();
  273. });
  274. });
  275. },
  276. },
  277. ];
  278. },
  279. },
  280. ];
  281. });
  282. const uploadData = ref({});
  283. const fileList = ref([]);
  284. const fileListCopy = ref([]);
  285. let formData = reactive({
  286. data: {},
  287. });
  288. const formOption = reactive({
  289. disabled: false,
  290. inline: true,
  291. labelWidth: 100,
  292. itemWidth: 100,
  293. rules: [],
  294. });
  295. const byform = ref(null);
  296. const formConfig = computed(() => {
  297. return [
  298. {
  299. type: "title",
  300. title: "基本信息",
  301. },
  302. {
  303. type: "treeSelect",
  304. prop: "productClassifyId",
  305. label: "产品分类",
  306. data: treeListData.value,
  307. itemWidth: 100,
  308. disabled: false,
  309. style: {
  310. width: "100%",
  311. },
  312. },
  313. {
  314. type: "input",
  315. prop: "name",
  316. label: "产品名称",
  317. itemWidth: 100,
  318. disabled: false,
  319. },
  320. {
  321. type: "slot",
  322. slotName: "nameEnglish",
  323. label: "",
  324. },
  325. {
  326. type: "slot",
  327. slotName: "productPic",
  328. prop: "fileList",
  329. label: "产品图片",
  330. },
  331. {
  332. type: "title",
  333. title: "价格信息",
  334. },
  335. {
  336. type: "selectInput",
  337. prop: "price",
  338. selectProp: "currency",
  339. label: "销售指导价",
  340. itemWidth: 50,
  341. style: {
  342. width: "100%",
  343. },
  344. data: accountCurrency.value,
  345. },
  346. {
  347. type: "selectInput",
  348. prop: "costPrice",
  349. selectProp: "costCurrency",
  350. label: "成本价",
  351. itemWidth: 50,
  352. style: {
  353. width: "100%",
  354. },
  355. data: accountCurrency.value,
  356. },
  357. {
  358. type: "title",
  359. title: "属性信息",
  360. },
  361. {
  362. type: "input",
  363. prop: "spec",
  364. label: "规格型号",
  365. itemWidth: 100,
  366. disabled: false,
  367. },
  368. {
  369. type: "input",
  370. prop: "productLong",
  371. label: "尺寸",
  372. itemWidth: 33.33,
  373. placeholder: "长(cm)",
  374. disabled: false,
  375. },
  376. {
  377. type: "input",
  378. prop: "productWide",
  379. label: " ",
  380. itemWidth: 33.33,
  381. placeholder: "宽(cm)",
  382. disabled: false,
  383. },
  384. {
  385. type: "input",
  386. prop: "productHigh",
  387. label: " ",
  388. itemWidth: 33.33,
  389. placeholder: "高(cm)",
  390. disabled: false,
  391. },
  392. {
  393. type: "select",
  394. prop: "innerPackMethod",
  395. label: "内包装方式",
  396. required: true,
  397. itemWidth: 50,
  398. multiple: true,
  399. data: innerMethon.value,
  400. filterable: true,
  401. placeholder: "内包装方式",
  402. style: {
  403. width: "100%",
  404. },
  405. disabled: false,
  406. },
  407. {
  408. type: "select",
  409. prop: "outerPackMethod",
  410. label: "外包装方式",
  411. required: true,
  412. itemWidth: 50,
  413. multiple: true,
  414. data: outsideMethon.value,
  415. filterable: true,
  416. placeholder: "外包装方式",
  417. style: {
  418. width: "100%",
  419. },
  420. disabled: false,
  421. },
  422. {
  423. type: "input",
  424. prop: "netWeight",
  425. label: "净重(kg)",
  426. itemWidth: 100,
  427. style: {
  428. width: "30%",
  429. },
  430. },
  431. {
  432. type: "input",
  433. prop: "hsCode",
  434. label: "海关编码",
  435. itemWidth: 100,
  436. style: {
  437. width: "30%",
  438. },
  439. disabled: false,
  440. },
  441. {
  442. type: "input",
  443. itemType: "textarea",
  444. prop: "remark",
  445. label: "备注",
  446. itemWidth: 100,
  447. },
  448. ];
  449. });
  450. const getList = async (req) => {
  451. sourceList.value.pagination = { ...sourceList.value.pagination, ...req };
  452. loading.value = true;
  453. proxy
  454. .post("/productInfo/getConditionProductList", sourceList.value.pagination)
  455. .then(
  456. (message) => {
  457. sourceList.value.data = message.rows.map((x) => ({
  458. ...x,
  459. fileList: [],
  460. ...JSON.parse(x.ehsdJson),
  461. }));
  462. sourceList.value.pagination.total = message.total;
  463. setTimeout(() => {
  464. loading.value = false;
  465. }, 200);
  466. const productIdList = message.rows.map((x) => x.id);
  467. // 请求文件数据并回显
  468. if (productIdList.length > 0) {
  469. proxy
  470. .post("/fileInfo/getList", {
  471. businessIdList: productIdList,
  472. })
  473. .then((fileObj) => {
  474. for (let i = 0; i < sourceList.value.data.length; i++) {
  475. const e = sourceList.value.data[i];
  476. for (const key in fileObj) {
  477. if (e.id === key) {
  478. e.fileList = fileObj[key];
  479. }
  480. }
  481. }
  482. });
  483. }
  484. },
  485. (err) => {
  486. loading.value = false;
  487. }
  488. );
  489. };
  490. const treeChange = (e) => {
  491. sourceList.value.pagination.productClassifyId = e.id;
  492. getList({ productClassifyId: e.id });
  493. };
  494. const openModal = () => {
  495. dialogVisible.value = true;
  496. modalType.value = "add";
  497. formData.data = {
  498. definition: "1",
  499. outerPackMethod: [],
  500. innerPackMethod: [],
  501. fileList: [],
  502. fileListCopy: [],
  503. currency: "",
  504. costCurrency: "",
  505. };
  506. if (accountCurrency.value && accountCurrency.value.length > 0) {
  507. formData.data.currency = accountCurrency.value[0].value;
  508. formData.data.costCurrency = accountCurrency.value[0].value;
  509. }
  510. fileList.value = [];
  511. fileListCopy.value = [];
  512. };
  513. const openExcel = () => {
  514. openExcelDialog.value = true;
  515. };
  516. const needAtt = [
  517. "productClassifyId",
  518. "name",
  519. "spec",
  520. "remark",
  521. "fileList",
  522. "id",
  523. "unit",
  524. "definition",
  525. ];
  526. const submitForm = () => {
  527. byform.value.handleSubmit((valid) => {
  528. // if (!fileListCopy.value.length > 0) {
  529. // return ElMessage({
  530. // message: "请上传产品图片",
  531. // type: "info",
  532. // });
  533. // }
  534. let jsonObj = {};
  535. formData.data.fileList = fileListCopy.value.map((x) => ({
  536. id: x.id,
  537. fileName: x.fileName,
  538. }));
  539. for (const key in formData.data) {
  540. if (needAtt.includes(key)) {
  541. } else {
  542. jsonObj[key] = formData.data[key];
  543. delete formData.data[key];
  544. }
  545. }
  546. jsonObj.innerPackMethod = jsonObj.innerPackMethod.join(",");
  547. jsonObj.outerPackMethod = jsonObj.outerPackMethod.join(",");
  548. jsonObj.type = "1"; //1为公司产品库
  549. formData.data.ehsdJson = JSON.stringify(jsonObj);
  550. submitLoading.value = true;
  551. proxy.post(`/productInfo/${modalType.value}ByEhsd`, formData.data).then(
  552. (res) => {
  553. ElMessage({
  554. message: modalType.value == "add" ? "添加成功" : "编辑成功",
  555. type: "success",
  556. });
  557. dialogVisible.value = false;
  558. submitLoading.value = false;
  559. getList();
  560. },
  561. (err) => {
  562. for (const key in jsonObj) {
  563. formData.data[key] = jsonObj[key];
  564. }
  565. formData.data.innerPackMethod =
  566. formData.data.innerPackMethod.split(",");
  567. formData.data.outerPackMethod =
  568. formData.data.outerPackMethod.split(",");
  569. submitLoading.value = false;
  570. }
  571. );
  572. });
  573. };
  574. const getTreeList = () => {
  575. proxy
  576. .post("/productClassify/tree", { parentId: "", name: "", definition: "1" })
  577. .then((message) => {
  578. treeListData.value = message;
  579. });
  580. };
  581. const getDtl = (row) => {
  582. modalType.value = "edit";
  583. proxy.post("/productInfo/detailByEhsd", { id: row.id }).then((res) => {
  584. res.definition = "1"; //产品
  585. let jsonObj = JSON.parse(res.ehsdJson);
  586. res = {
  587. ...res,
  588. currency: jsonObj.currency
  589. ? jsonObj.currency
  590. : accountCurrency.value[0].value,
  591. costCurrency: jsonObj.costCurrency
  592. ? jsonObj.costCurrency
  593. : accountCurrency.value[0].value,
  594. ...jsonObj,
  595. };
  596. if (res.innerPackMethod) {
  597. res.innerPackMethod = res.innerPackMethod.split(",");
  598. } else {
  599. res.innerPackMethod = [];
  600. }
  601. if (res.outerPackMethod) {
  602. res.outerPackMethod = res.outerPackMethod.split(",");
  603. } else {
  604. res.outerPackMethod = [];
  605. }
  606. formData.data = res;
  607. dialogVisible.value = true;
  608. proxy
  609. .post("/fileInfo/getList", { businessIdList: [row.id] })
  610. .then((fileObj) => {
  611. if (fileObj[row.id]) {
  612. fileList.value = fileObj[row.id].map((x) => ({
  613. ...x,
  614. url: x.fileUrl,
  615. }));
  616. fileListCopy.value = fileObj[row.id].map((x) => ({
  617. ...x,
  618. url: x.fileUrl,
  619. }));
  620. } else {
  621. fileList.value = [];
  622. fileListCopy.value = [];
  623. }
  624. });
  625. });
  626. };
  627. const isdisabled = ["price", "costPrice", "remark", "netWeight"];
  628. // watch(modalType, (val) => {
  629. // if (val) {
  630. // for (let i = 0; i < formConfig.value.length; i++) {
  631. // const element = formConfig.value[i];
  632. // if (element.type != "title" || element.type != "slot") {
  633. // if (!isdisabled.includes(element.prop)) {
  634. // element.disabled = val == "edit" ? true : false;
  635. // }
  636. // }
  637. // }
  638. // }
  639. // });
  640. const handleBeforeUpload = async (file) => {
  641. const res = await proxy.post("/fileInfo/getSing", { fileName: file.name });
  642. uploadData.value = res.uploadBody;
  643. fileListCopy.value.push({
  644. id: res.id,
  645. fileName: res.fileName,
  646. path: res.fileUrl,
  647. url: res.fileUrl,
  648. uid: file.uid,
  649. });
  650. };
  651. const handleRemove = (file) => {
  652. const index = fileListCopy.value.findIndex(
  653. (x) => x.uid === file.uid || x.id === file.id
  654. );
  655. fileListCopy.value.splice(index, 1);
  656. };
  657. const handleClickFile = (file) => {
  658. window.open(file.fileUrl, "_blank");
  659. };
  660. const handleProgress = () => {
  661. excelLoading.value = true;
  662. };
  663. const handleError = (err) => {
  664. ElMessage({
  665. message: `${err},请重试!`,
  666. type: "info",
  667. });
  668. openExcelDialog.value = false;
  669. excelLoading.value = false;
  670. };
  671. const handleSuccess = (res) => {
  672. if (res.code != 200) {
  673. return ElMessage({
  674. message: `${res.msg},请重试!`,
  675. type: "info",
  676. });
  677. } else {
  678. ElMessage({
  679. message: "导入成功!",
  680. type: "success",
  681. });
  682. openExcelDialog.value = false;
  683. excelLoading.value = false;
  684. getList();
  685. }
  686. };
  687. const getDict = () => {
  688. proxy
  689. .getDictOne([
  690. "inner_packaging_method_ehsd",
  691. "outside_packaging_method_ehsd",
  692. "unit",
  693. "account_currency",
  694. ])
  695. .then((res) => {
  696. innerMethon.value = res["inner_packaging_method_ehsd"].map((x) => ({
  697. label: x.dictValue,
  698. value: x.dictKey,
  699. }));
  700. outsideMethon.value = res["outside_packaging_method_ehsd"].map((x) => ({
  701. label: x.dictValue,
  702. value: x.dictKey,
  703. }));
  704. productUnit.value = res["unit"].map((x) => ({
  705. label: x.dictValue,
  706. value: x.dictKey,
  707. }));
  708. accountCurrency.value = res["account_currency"].map((x) => ({
  709. label: x.dictValue,
  710. value: x.dictKey,
  711. }));
  712. });
  713. };
  714. getDict();
  715. getTreeList();
  716. getList();
  717. const clickSelect = (item) => {
  718. proxy.$emit("selectProduct", item);
  719. };
  720. const handleKeypress = (event) => {
  721. // 判断输入字符是否为中文字符
  722. if (event.key.match(/[\u4e00-\u9fa5]/)) {
  723. // 阻止输入
  724. event.preventDefault();
  725. }
  726. };
  727. const handleKeyup = (val) => {
  728. // 过滤掉中文字符
  729. formData.data.nameEnglish = formData.data.nameEnglish.replace(
  730. /[\u4e00-\u9fa5]/g,
  731. ""
  732. );
  733. };
  734. const handlePreview = (file) => {
  735. if (file && file.fileUrl) {
  736. window.open(file.fileUrl, "_black");
  737. }
  738. };
  739. const productContractDialog = ref(false);
  740. const currentProductId = ref("");
  741. const handleOpenProductContract = (row) => {
  742. currentProductId.value = row.id;
  743. productContractDialog.value = true;
  744. };
  745. </script>
  746. <style lang="scss" scoped>
  747. .user {
  748. padding: 20px;
  749. display: flex;
  750. justify-content: space-between;
  751. .tree {
  752. width: 300px;
  753. }
  754. .content {
  755. width: calc(100% - 320px);
  756. }
  757. }
  758. .pic {
  759. object-fit: contain;
  760. width: 50px;
  761. height: 50px;
  762. cursor: pointer;
  763. vertical-align: middle;
  764. }
  765. </style>