index.vue 21 KB

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