From 692451959df42c10d489d866dcae48a121bd9dd0 Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期二, 20 五月 2025 17:51:24 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/dev' into dev

---
 src/views/basicData/product/index.vue |  385 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 385 insertions(+), 0 deletions(-)

diff --git a/src/views/basicData/product/index.vue b/src/views/basicData/product/index.vue
new file mode 100644
index 0000000..dba78e3
--- /dev/null
+++ b/src/views/basicData/product/index.vue
@@ -0,0 +1,385 @@
+<template>
+  <div class="app-container product-view">
+    <div class="left">
+      <div>
+        <el-input
+            v-model="search"
+            style="width: 240px"
+            placeholder="杈撳叆鍏抽敭瀛楄繘琛屾悳绱�"
+            @change="searchFilter"
+            @clear="searchFilter"
+            clearable
+            prefix-icon="Search"
+        />
+        <el-button type="primary" @click="openProDia('add')" style="margin-left: 10px">鏂板浜у搧</el-button>
+      </div>
+      <div>
+        <el-tree ref="tree" v-loading="treeLoad" :data="list" @node-click="handleNodeClick"
+                 :expand-on-click-node="false"
+                 :default-expanded-keys="expandedKeys" :draggable="true" :filter-node-method="filterNode"
+                 :props="{ children: 'children', label: 'label' }" highlight-current node-key="id"
+                 style="height: calc(100vh - 190px);overflow-y: scroll;scrollbar-width: none;">
+          <template #default="{ node, data }">
+            <div class="custom-tree-node">
+              <span>{{ node.label }}</span>
+              <div>
+                <el-button type="primary" link @click="openProDia('edit', data)">
+                  缂栬緫
+                </el-button>
+                <!-- 淇敼姝ゅ -->
+                <el-button
+                    v-if="!node.childNodes.length"
+                    style="margin-left: 4px"
+                    type="danger"
+                    link
+                    @click="remove(node, data)"
+                >
+                  鍒犻櫎
+                </el-button>
+              </div>
+            </div>
+          </template>
+        </el-tree>
+      </div>
+    </div>
+    <div class="right">
+      <div style="margin-bottom: 10px">
+        <el-button type="primary" @click="openModelDia('add')">鏂板瑙勬牸鍨嬪彿</el-button>
+        <el-button type="danger" @click="handleDelete" style="margin-left: 10px" plain>鍒犻櫎</el-button>
+      </div>
+      <PIMTable :column="tableColumn" :tableData="tableData" :page="page" :isSelection="true" :handleSelectionChange="handleSelectionChange"
+                :tableLoading="tableLoading" @pagination="pagination" :total="total"></PIMTable>
+    </div>
+    <el-dialog v-model="productDia" title="浜у搧" width="400px">
+      <el-form :model="form" label-width="140px" label-position="top" :rules="rules" ref="formRef">
+        <el-row :gutter="30">
+          <el-col :span="24">
+            <el-form-item label="浜у搧鍚嶇О锛�" prop="productName">
+              <el-input v-model="form.productName" placeholder="璇疯緭鍏ヤ骇鍝佸悕绉�" clearable/>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="submitForm">纭</el-button>
+          <el-button @click="closeProDia">鍙栨秷</el-button>
+        </div>
+      </template>
+    </el-dialog>
+    <el-dialog v-model="modelDia" title="浜у搧" width="400px">
+      <el-form :model="modelForm" label-width="140px" label-position="top" :rules="modelRules" ref="modelFormRef">
+        <el-row>
+          <el-col :span="24">
+            <el-form-item label="瑙勬牸鍨嬪彿锛�" prop="model">
+              <el-input v-model="modelForm.model" placeholder="璇疯緭鍏ヨ鏍煎瀷鍙�" clearable/>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="24">
+            <el-form-item label="鍗曚綅锛�" prop="unit">
+              <el-input v-model="modelForm.unit" placeholder="璇疯緭鍏ュ崟浣�" clearable/>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="submitModelForm">纭</el-button>
+          <el-button @click="closeProDia">鍙栨秷</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+import {ref} from "vue";
+import {ElMessageBox} from "element-plus";
+import {
+  addOrEditProduct,
+  addOrEditProductModel,
+  delProduct, delProductModel,
+  modelList,
+  productTreeList
+} from "@/api/basicData/product.js";
+const { proxy } = getCurrentInstance()
+
+const productDia = ref(false)
+const modelDia = ref(false)
+const modelOperationType = ref('')
+const search = ref('')
+const currentId = ref('')
+const currentParentId = ref('')
+const operationType = ref('')
+const treeLoad = ref(false)
+const list = ref([])
+const expandedKeys = ref([])
+const tableColumn = ref([
+  {
+    label: '瑙勬牸鍨嬪彿',
+    prop: 'model',
+  },
+  {
+    label: '鍗曚綅',
+    prop: 'unit',
+  },
+  {
+    dataType: "action",
+    label: "鎿嶄綔",
+    align: 'center',
+    operation: [
+      {
+        name: "缂栬緫",
+        type: "text",
+        clickFun: (row) => {
+          openModelDia('edit', row);
+        },
+      },
+    ],
+  },
+])
+const tableData = ref([])
+const tableLoading = ref(false)
+const total = ref(0)
+const selectedRows = ref([])
+const page = reactive({
+  current: 1,
+  size: 10,
+})
+const data = reactive({
+  form: {
+    productName: '',
+  },
+  rules: {
+    productName: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+  },
+  modelForm: {
+    model: '',
+    unit: '',
+  },
+  modelRules: {
+    model: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+    unit: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+  }
+})
+const { form, rules, modelForm, modelRules } = toRefs(data)
+// 鏌ヨ浜у搧鏍�
+const getProductTreeList = () => {
+  treeLoad.value = true;
+  productTreeList().then(res => {
+    list.value = res
+    list.value.forEach((a) => {
+      expandedKeys.value.push(a.label);
+    });
+    treeLoad.value = false;
+  }).catch(err => {
+    treeLoad.value = false;
+  })
+}
+// 杩囨护浜у搧鏍�
+const searchFilter = () => {
+  proxy.$refs.tree.filter(search.value);
+}
+// 鎵撳紑浜у搧寮规
+const openProDia = (type, data) => {
+  operationType.value = type;
+  productDia.value = true
+  form.value.productName = ''
+  if (type === 'edit') {
+    form.value.productName = data.productName
+  }
+}
+// 鎵撳紑瑙勬牸鍨嬪彿寮规
+const openModelDia = (type, data) => {
+  modelOperationType.value = type;
+  modelDia.value = true
+  modelForm.value.model = ''
+  modelForm.value.model = ''
+  modelForm.value.id = ''
+  if (type === 'edit') {
+    modelForm.value = {...data}
+  }
+}
+// 鎻愪氦浜у搧鍚嶇О淇敼
+const submitForm = () => {
+  proxy.$refs.formRef.validate(valid => {
+    if (valid) {
+      if (operationType.value === 'add') {
+        form.value.parentId = currentId.value
+        form.value.id = ''
+      } else {
+        form.value.id = currentId.value
+        form.value.parentId = ''
+      }
+      addOrEditProduct(form.value).then(res => {
+        proxy.$modal.msgSuccess("鎻愪氦鎴愬姛")
+        closeProDia()
+        getProductTreeList()
+      })
+    }
+  })
+}
+// 鍏抽棴浜у搧寮规
+const closeProDia = () => {
+  proxy.$refs.formRef.resetFields();
+  productDia.value = false;
+}
+// 鍒犻櫎浜у搧
+const remove = (node, data) => {
+  let ids = []
+  ids.push(data.id)
+  ElMessageBox.confirm(
+      '閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�',
+      '鍒犻櫎鎻愮ず', {
+        confirmButtonText: '纭',
+        cancelButtonText: '鍙栨秷',
+        type: 'warning',
+      }
+  ).then(() => {
+    tableLoading.value = true
+    delProduct(ids).then(res => {
+      proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛")
+      getProductTreeList()
+    }).finally(() => {
+      tableLoading.value = false
+    })
+  }).catch(() => {
+    proxy.$modal.msg("宸插彇娑�")
+  })
+}
+// 閫夋嫨浜у搧
+const handleNodeClick = (val, node, el) => {
+  currentId.value = val.id
+  currentParentId.value = val.parentId
+  getModelList()
+}
+
+
+// 鎻愪氦瑙勬牸鍨嬪彿淇敼
+const submitModelForm = () => {
+  proxy.$refs.modelFormRef.validate(valid => {
+    if (valid) {
+      modelForm.value.productId = currentId.value
+      addOrEditProductModel(modelForm.value).then(res => {
+        proxy.$modal.msgSuccess("鎻愪氦鎴愬姛")
+        closeModelDia()
+        getModelList()
+      })
+    }
+  })
+}
+// 鍏抽棴浜у搧寮规
+const closeModelDia = () => {
+  proxy.$refs.modelFormRef.resetFields();
+  modelDia.value = false;
+}
+// 琛ㄦ牸閫夋嫨鏁版嵁
+const handleSelectionChange = (selection) => {
+  selectedRows.value = selection
+}
+
+// 鏌ヨ瑙勬牸鍨嬪彿
+const pagination = ({ current, limit }) => {
+  page.current = current;
+  page.size = limit;
+  getModelList()
+}
+const getModelList = () => {
+  tableLoading.value = true
+  modelList({id: currentId.value}).then(res => {
+    tableLoading.value = false
+    tableData.value = res
+  })
+}
+// 鍒犻櫎瑙勬牸鍨嬪彿
+const handleDelete = () => {
+  let ids = []
+  if (selectedRows.value.length > 0) {
+    ids = selectedRows.value.map(item => item.id);
+  } else {
+    proxy.$modal.msgWarning('璇烽�夋嫨鏁版嵁')
+    return
+  }
+  ElMessageBox.confirm(
+      '閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�',
+      '鍒犻櫎鎻愮ず', {
+        confirmButtonText: '纭',
+        cancelButtonText: '鍙栨秷',
+        type: 'warning',
+      }
+  ).then(() => {
+    tableLoading.value = true
+    delProductModel(ids).then(res => {
+      proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛")
+      getModelList()
+    }).finally(() => {
+      tableLoading.value = false
+    })
+  }).catch(() => {
+    proxy.$modal.msg("宸插彇娑�")
+  })
+}
+// 璋冪敤tree杩囨护鏂规硶 涓枃鑻辫繃婊�
+const filterNode = (value, data, node) => {
+  if (!value) {銆�銆�銆�銆�//濡傛灉鏁版嵁涓虹┖锛屽垯杩斿洖true,鏄剧ず鎵�鏈夌殑鏁版嵁椤�
+    return true
+  }
+  // 鏌ヨ鍒楄〃鏄惁鏈夊尮閰嶆暟鎹紝灏嗗�煎皬鍐欙紝鍖归厤鑻辨枃鏁版嵁
+  let val = value.toLowerCase()
+  return chooseNode(val, data, node) // 璋冪敤杩囨护浜屽眰鏂规硶
+}
+// 杩囨护鐖惰妭鐐� / 瀛愯妭鐐� (濡傛灉杈撳叆鐨勫弬鏁版槸鐖惰妭鐐逛笖鑳藉尮閰嶏紝鍒欒繑鍥炶鑺傜偣浠ュ強鍏朵笅鐨勬墍鏈夊瓙鑺傜偣锛涘鏋滃弬鏁版槸瀛愯妭鐐癸紝鍒欒繑鍥炶鑺傜偣鐨勭埗鑺傜偣銆俷ame鏄腑鏂囧瓧绗︼紝enName鏄嫳鏂囧瓧绗�.
+const chooseNode = (value, data, node) => {
+  if (data.label.indexOf(value) !== -1) {
+    return true
+  }
+  const level = node.level
+  // 濡傛灉浼犲叆鐨勮妭鐐规湰韬氨鏄竴绾ц妭鐐瑰氨涓嶇敤鏍¢獙浜�
+  if (level === 1) {
+    return false
+  }
+  // 鍏堝彇褰撳墠鑺傜偣鐨勭埗鑺傜偣
+  let parentData = node.parent
+  // 閬嶅巻褰撳墠鑺傜偣鐨勭埗鑺傜偣
+  let index = 0
+  while (index < level - 1) {
+    // 濡傛灉鍖归厤鍒扮洿鎺ヨ繑鍥烇紝姝ゅname鍊兼槸涓枃瀛楃锛宔nName鏄嫳鏂囧瓧绗︺�傚垽鏂尮閰嶄腑鑻辨枃杩囨护
+    if (parentData.data.label.indexOf(value) !== -1) {
+      return true
+    }
+    // 鍚﹀垯鐨勮瘽鍐嶅線涓婁竴灞傚仛鍖归厤
+    parentData = parentData.parent
+    index++
+  }
+  // 娌″尮閰嶅埌杩斿洖false
+  return false
+}
+getProductTreeList()
+</script>
+
+<style scoped>
+.product-view {
+  display: flex;
+}
+.left {
+  width: 380px;
+  padding: 16px;
+  background: #ffffff;
+}
+.right {
+  width: calc(100% - 380px);
+  padding: 16px;
+  margin-left: 20px;
+  background: #ffffff;
+}
+.custom-tree-node {
+  flex: 1;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  font-size: 14px;
+  padding-right: 8px;
+}
+</style>
\ No newline at end of file

--
Gitblit v1.9.3