Ver código fonte

添加商品分类,调整产品新增

yangg 11 meses atrás
pai
commit
466eddc584

+ 2 - 1
.env

@@ -1,5 +1,6 @@
-VITE_API_URL=https://api.raycos.net
+VITE_API_URL=http://192.168.1.178:9998
 #线下地址
 #http://192.168.1.178:9998
+#http://192.168.1.141:9998
 #线上地址
 #https://api.raycos.net

+ 109 - 1
src/api/goods.js

@@ -36,4 +36,112 @@ export function editProduct(id,params) {
       method: 'post',
       headers: { 'Content-Type': 'application/json' },
     })
-  }
+  }
+/**
+ * 添加分类
+ * @param params
+ */
+export function addCategory(params) {
+  const _params = {
+    name: params.category_name,
+    parent_id: params.parent_id ? params.parent_id : '0',
+    customSn: params.custom_sn,
+    is_show: 'YES'
+  }
+  return request({
+    url: 'admin/goods/categories',
+    method: 'post',
+    data: _params
+  })
+}
+
+/**
+ * 编辑分类
+ * @param id
+ * @param params
+ */
+export function editCategory(id, params) {
+  const _params = {
+    name: params.category_name,
+    parent_id: params.parent_id ? params.parent_id : '0',
+    customSn: params.custom_sn
+  }
+  return request({
+    url: `admin/goods/categories/${id}`,
+    method: 'put',
+    data: _params
+  })
+}
+/**
+ * 修改分类关联规格
+ * @param ids
+ * @returns {*}
+ */
+export function updateCategorySpecs(category_id, choose_specs) {
+  return request({
+    url: `admin/goods/categories/specs/${category_id}`,
+    method: 'put',
+    data: { choose_specs }
+  })
+}
+/**
+ * 根据分类ID获取分类关联规格数据
+ * @param category_id
+ * @returns {Promise<any>}
+ */
+export function getSpecsByCategoryId(category_id) {
+  return request({
+    url: `admin/goods/categories/${category_id}/specs`,
+    method: 'get'
+  })
+}
+
+/**
+ * 删除分类
+ * @param ids
+ * @returns {*}
+ */
+export function deleteCategory(ids) {
+  if (Array.isArray(ids)) ids = ids.join(',')
+  return request({
+    url: `admin/goods/categories/${ids}`,
+    method: 'delete'
+  })
+}
+
+/**
+ * 获取分类子集
+ * @param parent_id
+ */
+export function getCategoryChildren(parent_id = 0) {
+  return request({
+    url: `admin/goods/categories/${parent_id}/children`,
+    method: 'get',
+    loading: false
+  })
+}
+
+/**
+ * 获取分类全部
+ * @param parent_id
+ */
+export function getCategoryAllChildren(parent_id = "0") {
+  return request({
+    url: `admin/goods/categories/${parent_id}/all-children`,
+    method: 'get',
+    // params,
+    loading: false
+  })
+}
+
+/**
+ * 获取分类关联的参数
+ * @param category_id 分类ID
+ * @returns {*}
+ */
+export function getCategoryParams(category_id) {
+  return request({
+    url: `admin/goods/categories/${category_id}/param`,
+    method: 'get'
+  })
+}

BIN
src/assets/images/logo.png


BIN
src/assets/images/setting.png


BIN
src/assets/images/模版管理.png


+ 74 - 308
src/components/layout/Header.vue

@@ -4,9 +4,9 @@
       <div class="relative bg-white flex w-full items-center px-5 py-1.5 dark:bg-[#0e1726]">
         <div class="horizontal-logo flex lg:hidden justify-between items-center ltr:mr-2 rtl:ml-2">
           <router-link to="/dashboard" class="main-logo flex items-center shrink-0">
-            <img class="w-full h-10 ltr:-ml-1 rtl:-mr-1 inline" src="https://www.raycos.com.cn/theme/m049/images/logo.png" alt="" />
+            <img class="w-full h-10 ltr:-ml-1 rtl:-mr-1 inline" src="../../assets/images/logo.png" alt="" />
             <!-- <span class="text-2xl ltr:ml-1.5 rtl:mr-1.5 font-semibold align-middle hidden md:inline dark:text-white-light transition-all duration-300"
-              >V3studio App</span
+              >V3studio App</span https://www.raycos.com.cn/theme/m049/images/logo.png
             > -->
           </router-link>
           <!-- 原导航 -->
@@ -251,6 +251,7 @@
         </div>
       </div>
       <ul
+        v-if="superMenu == 'compan'"
         style="box-shadow: 0 0px 0px #ccc"
         class="horizontal-menu hidden py-1.5 font-semibold px-6 lg:space-x-1.5 xl:space-x-8 rtl:space-x-reverse bg-white border-t border-[#ebedf2] dark:border-[#191e3a] dark:bg-[#0e1726] text-black dark:text-white-dark"
       >
@@ -268,12 +269,12 @@
         <li class="menu nav-item relative">
           <a href="javascript:;" class="nav-link">
             <div class="flex items-center">
-             <!--  <icon-menu-dashboard class="shrink-0" /> -->
-              <img src="../../assets/images/warehouse.png" width="20px" alt="">
+              <!--  <icon-menu-dashboard class="shrink-0" /> -->
+              <img src="../../assets/images/warehouse.png" width="20px" alt="" />
               <span class="px-2">{{ $t('warehouse') }}</span>
             </div>
             <div class="right_arrow">
-             <!--  <icon-caret-down /> -->
+              <!--  <icon-caret-down /> -->
             </div>
           </a>
           <ul class="sub-menu">
@@ -321,12 +322,15 @@
             <li>
               <router-link to="/goods/SKUlist">{{ $t('SKUList') }}</router-link>
             </li>
+            <li>
+              <router-link to="/goods/category">{{ $t('category') }}</router-link>
+            </li>
           </ul>
         </li>
         <li class="menu nav-item relative">
           <a href="javascript:;" class="nav-link">
             <div class="flex items-center">
-              <img src="../../assets/images/order.png" width="20px" alt="">
+              <img src="../../assets/images/order.png" width="20px" alt="" />
               <!-- <icon-menu-components class="shrink-0" /> -->
               <span class="px-2">{{ $t('order') }}</span>
             </div>
@@ -340,6 +344,23 @@
             </li>
           </ul>
         </li>
+        <li class="menu nav-item relative">
+          <a href="javascript:;" class="nav-link">
+            <div class="flex items-center">
+              <!-- <img src="../../assets/images/order.png" width="20px" alt="" /> -->
+              <!-- <icon-menu-components class="shrink-0" /> -->
+              <span class="px-2">{{ $t('procure') }}</span>
+            </div>
+            <div class="right_arrow">
+              <!-- <icon-caret-down /> -->
+            </div>
+          </a>
+          <ul class="sub-menu">
+            <li>
+              <router-link to="/procure/purchaseOrder">{{ $t('purchaseOrder') }}</router-link>
+            </li>
+          </ul>
+        </li>
         <li class="menu nav-item relative">
           <a href="javascript:;" class="nav-link">
             <div class="flex items-center">
@@ -368,372 +389,117 @@
             </li>
           </ul>
         </li>
-        <!-- <li class="menu nav-item relative">
+      </ul>
+      <ul
+        v-if="superMenu == 'super'"
+        style="box-shadow: 0 0px 0px #ccc"
+        class="horizontal-menu hidden py-1.5 font-semibold px-6 lg:space-x-1.5 xl:space-x-8 rtl:space-x-reverse bg-white border-t border-[#ebedf2] dark:border-[#191e3a] dark:bg-[#0e1726] text-black dark:text-white-dark"
+      >
+        <li class="menu nav-item relative">
           <a href="javascript:;" class="nav-link">
             <div class="flex items-center">
-              <icon-menu-elements class="shrink-0" />
-              <span class="px-2">{{ $t('elements') }}</span>
-            </div>
-            <div class="right_arrow">
-              <icon-caret-down />
+              <icon-menu-dashboard class="shrink-0" />
+              <router-link to="/dashboard" class="px-2">{{ $t('home') }}</router-link>
             </div>
           </a>
-          <ul class="sub-menu">
-            <li>
-              <router-link to="/elements/alerts">{{ $t('alerts') }}</router-link>
-            </li>
-            <li>
-              <router-link to="/elements/avatar">{{ $t('avatar') }}</router-link>
-            </li>
-            <li>
-              <router-link to="/elements/badges">{{ $t('badges') }}</router-link>
-            </li>
-            <li>
-              <router-link to="/elements/breadcrumbs">{{ $t('breadcrumbs') }}</router-link>
-            </li>
-            <li>
-              <router-link to="/elements/buttons">{{ $t('buttons') }}</router-link>
-            </li>
-            <li>
-              <router-link to="/elements/buttons-group">{{ $t('button_groups') }}</router-link>
-            </li>
-            <li>
-              <router-link to="/elements/color-library">{{ $t('color_library') }}</router-link>
-            </li>
-            <li>
-              <router-link to="/elements/dropdown">{{ $t('dropdown') }}</router-link>
-            </li>
-            <li>
-              <router-link to="/elements/infobox">{{ $t('infobox') }}</router-link>
-            </li>
-            <li>
-              <router-link to="/elements/jumbotron">{{ $t('jumbotron') }}</router-link>
-            </li>
-            <li>
-              <router-link to="/elements/loader">{{ $t('loader') }}</router-link>
-            </li>
-            <li>
-              <router-link to="/elements/pagination">{{ $t('pagination') }}</router-link>
-            </li>
-            <li>
-              <router-link to="/elements/popovers">{{ $t('popovers') }}</router-link>
-            </li>
-            <li>
-              <router-link to="/elements/progress-bar">{{ $t('progress_bar') }}</router-link>
-            </li>
-            <li>
-              <router-link to="/elements/search">{{ $t('search') }}</router-link>
-            </li>
-            <li>
-              <router-link to="/elements/tooltips">{{ $t('tooltips') }}</router-link>
-            </li>
-            <li>
-              <router-link to="/elements/treeview">{{ $t('treeview') }}</router-link>
-            </li>
-            <li>
-              <router-link to="/elements/typography">{{ $t('typography') }}</router-link>
-            </li>
-          </ul>
         </li>
         <li class="menu nav-item relative">
           <a href="javascript:;" class="nav-link">
             <div class="flex items-center">
-              <icon-menu-datatables class="shrink-0" />
-              <span class="px-2">{{ $t('tables') }}</span>
+              <!--  <icon-menu-dashboard class="shrink-0" /> -->
+              <!-- <img src="../../assets/images/warehouse.png" width="20px" alt="" /> -->
+              <icon-menu-apps class="shrink-0" />
+              <span class="px-2">{{ $t('package') }}</span>
             </div>
             <div class="right_arrow">
-              <icon-caret-down />
+              <!--  <icon-caret-down /> -->
             </div>
           </a>
           <ul class="sub-menu">
             <li>
-              <router-link to="/tables">{{ $t('tables') }}</router-link>
+              <router-link to="/package/packageList">{{ $t('packageList') }}</router-link>
             </li>
-            <li class="relative">
-              <a href="javascript:;"
-                >{{ $t('datatables') }}
-                <div class="ltr:ml-auto rtl:mr-auto rtl:rotate-90 -rotate-90">
-                  <icon-caret-down />
-                </div>
-              </a>
-              <ul
-                class="rounded absolute top-0 ltr:left-[95%] rtl:right-[95%] min-w-[180px] bg-white z-[10] text-dark dark:text-white-dark dark:bg-[#1b2e4b] shadow p-0 py-2 hidden"
-              >
-                <li>
-                  <router-link to="/datatables/basic">{{ $t('basic') }}</router-link>
-                </li>
-                <li>
-                  <router-link to="/datatables/advanced">{{ $t('advanced') }}</router-link>
-                </li>
-                <li>
-                  <router-link to="/datatables/skin">{{ $t('skin') }}</router-link>
-                </li>
-                <li>
-                  <router-link to="/datatables/order-sorting">{{ $t('order_sorting') }}</router-link>
-                </li>
-                <li>
-                  <router-link to="/datatables/columns-filter">{{ $t('columns_filter') }}</router-link>
-                </li>
-                <li>
-                  <router-link to="/datatables/multi-column">{{ $t('multi_column') }}</router-link>
-                </li>
-                <li>
-                  <router-link to="/datatables/multiple-tables">{{ $t('multiple_tables') }}</router-link>
-                </li>
-                <li>
-                  <router-link to="/datatables/alt-pagination">{{ $t('alt_pagination') }}</router-link>
-                </li>
-                <li>
-                  <router-link to="/datatables/checkbox">{{ $t('checkbox') }}</router-link>
-                </li>
-                <li>
-                  <router-link to="/datatables/range-search">{{ $t('range_search') }}</router-link>
-                </li>
-                <li>
-                  <router-link to="/datatables/export">{{ $t('export') }}</router-link>
-                </li>
-                <li>
-                  <router-link to="/datatables/sticky-header">{{ $t('sticky_header') }}</router-link>
-                </li>
-                <li>
-                  <router-link to="/datatables/clone-header">{{ $t('clone_header') }}</router-link>
-                </li>
-                <li>
-                  <router-link to="/datatables/column-chooser">{{ $t('column_chooser') }}</router-link>
-                </li>
-              </ul>
+            <li>
+              <router-link to="/package/packagePermissions">{{ $t('packagePermissions') }}</router-link>
             </li>
           </ul>
         </li>
         <li class="menu nav-item relative">
           <a href="javascript:;" class="nav-link">
             <div class="flex items-center">
-              <icon-menu-forms class="shrink-0" />
-              <span class="px-2">{{ $t('forms') }}</span>
+              <img src="../../assets/images/模版管理.png" width="20px" alt="" />
+              <!-- <icon-menu-apps class="shrink-0" /> -->
+              <span class="px-2">{{ $t('templateManage') }}</span>
             </div>
             <div class="right_arrow">
-              <icon-caret-down />
+              <!-- <icon-caret-down /> -->
             </div>
           </a>
           <ul class="sub-menu">
             <li>
-              <router-link to="/forms/basic">{{ $t('basic') }}</router-link>
-            </li>
-            <li>
-              <router-link to="/forms/input-group">{{ $t('input_group') }}</router-link>
-            </li>
-            <li>
-              <router-link to="/forms/layouts">{{ $t('layouts') }}</router-link>
-            </li>
-            <li>
-              <router-link to="/forms/validation">{{ $t('validation') }}</router-link>
-            </li>
-            <li>
-              <router-link to="/forms/input-mask">{{ $t('input_mask') }}</router-link>
-            </li>
-            <li>
-              <router-link to="/forms/select2">{{ $t('select2') }}</router-link>
-            </li>
-            <li>
-              <router-link to="/forms/touchspin">{{ $t('touchspin') }}</router-link>
-            </li>
-            <li>
-              <router-link to="/forms/checkbox-radio">{{ $t('checkbox_and_radio') }}</router-link>
-            </li>
-            <li>
-              <router-link to="/forms/switches">{{ $t('switches') }}</router-link>
-            </li>
-            <li>
-              <router-link to="/forms/wizards">{{ $t('wizards') }}</router-link>
-            </li>
-            <li>
-              <router-link to="/forms/file-upload">{{ $t('file_upload') }}</router-link>
-            </li>
-            <li>
-              <router-link to="/forms/quill-editor">{{ $t('quill_editor') }}</router-link>
+              <router-link to="/templateManage/smsTemplate">{{ $t('smsTemplate') }}</router-link>
             </li>
             <li>
-              <router-link to="/forms/markdown-editor">{{ $t('markdown_editor') }}</router-link>
+              <router-link to="/templateManage/emailtemplate">{{ $t('emailtemplate') }}</router-link>
             </li>
             <li>
-              <router-link to="/forms/date-picker">{{ $t('date_and_range_picker') }}</router-link>
+              <router-link to="/templateManage/accountTemplate">{{ $t('accountTemplate') }}</router-link>
             </li>
             <li>
-              <router-link to="/forms/clipboard">{{ $t('clipboard') }}</router-link>
+              <router-link to="/templateManage/systemMessage">{{ $t('systemMessage') }}</router-link>
             </li>
           </ul>
         </li>
         <li class="menu nav-item relative">
           <a href="javascript:;" class="nav-link">
             <div class="flex items-center">
-              <icon-menu-pages class="shrink-0" />
-              <span class="px-2">{{ $t('pages') }}</span>
+              <img src="../../assets/images/setting.png" width="20px" alt="" />
+              <!-- <icon-menu-components class="shrink-0" /> -->
+              <span class="px-2">{{ $t('setting') }}</span>
             </div>
             <div class="right_arrow">
-              <icon-caret-down />
+              <!-- <icon-caret-down /> -->
             </div>
           </a>
           <ul class="sub-menu">
-            <li class="relative">
-              <a href="javascript:;"
-                >{{ $t('users') }}
-                <div class="ltr:ml-auto rtl:mr-auto rtl:rotate-90 -rotate-90">
-                  <icon-caret-down />
-                </div>
-              </a>
-              <ul
-                class="rounded absolute top-0 ltr:left-[95%] rtl:right-[95%] min-w-[180px] bg-white z-[10] text-dark dark:text-white-dark dark:bg-[#1b2e4b] shadow p-0 py-2 hidden"
-              >
-                <li>
-                  <router-link to="/users/profile">{{ $t('profile') }}</router-link>
-                </li>
-                <li>
-                  <router-link to="/users/user-account-settings">{{ $t('account_settings') }}</router-link>
-                </li>
-              </ul>
-            </li>
-            <li>
-              <router-link to="/pages/knowledge-base">{{ $t('knowledge_base') }}</router-link>
-            </li>
-            <li>
-              <router-link to="/pages/contact-us-boxed" target="_blank">{{ $t('contact_us_boxed') }}</router-link>
-            </li>
             <li>
-              <router-link to="/pages/contact-us-cover" target="_blank">{{ $t('contact_us_cover') }}</router-link>
+              <router-link to="/setting/companyList">{{ $t('companyList') }}</router-link>
             </li>
             <li>
-              <router-link to="/pages/faq">FAQ</router-link>
+              <router-link to="/setting/dicData">{{ $t('dicData') }}</router-link>
             </li>
             <li>
-              <router-link to="/pages/coming-soon-boxed" target="_blank">{{ $t('coming_soon_boxed') }}</router-link>
+              <router-link to="/setting/menuManage">{{ $t('menuManage') }}</router-link>
             </li>
             <li>
-              <router-link to="/pages/coming-soon-cover" target="_blank">{{ $t('coming_soon_cover') }}</router-link>
-            </li>
-            <li>
-              <router-link to="/pages/maintenence" target="_blank">{{ $t('maintenence') }}</router-link>
-            </li>
-            <li class="relative">
-              <a href="javascript:;"
-                >{{ $t('error') }}
-                <div class="ltr:ml-auto rtl:mr-auto rtl:rotate-90 -rotate-90">
-                  <icon-caret-down />
-                </div>
-              </a>
-              <ul
-                class="rounded absolute top-0 ltr:left-[95%] rtl:right-[95%] min-w-[180px] bg-white z-[10] text-dark dark:text-white-dark dark:bg-[#1b2e4b] shadow p-0 py-2 hidden"
-              >
-                <li>
-                  <router-link to="/pages/error404" target="_blank">{{ $t('404') }}</router-link>
-                </li>
-                <li>
-                  <router-link to="/pages/error500" target="_blank">{{ $t('500') }}</router-link>
-                </li>
-                <li>
-                  <router-link to="/pages/error503" target="_blank">{{ $t('503') }}</router-link>
-                </li>
-              </ul>
-            </li>
-            <li class="relative">
-              <a href="javascript:;"
-                >{{ $t('login') }}
-                <div class="ltr:ml-auto rtl:mr-auto rtl:rotate-90 -rotate-90">
-                  <icon-caret-down />
-                </div>
-              </a>
-              <ul
-                class="rounded absolute top-0 ltr:left-[95%] rtl:right-[95%] min-w-[180px] bg-white z-[10] text-dark dark:text-white-dark dark:bg-[#1b2e4b] shadow p-0 py-2 hidden"
-              >
-                <li>
-                  <router-link to="/auth/cover-login" target="_blank">{{ $t('login_cover') }}</router-link>
-                </li>
-                <li>
-                  <router-link to="/auth/boxed-signin" target="_blank">{{ $t('login_boxed') }}</router-link>
-                </li>
-              </ul>
-            </li>
-            <li class="relative">
-              <a href="javascript:;"
-                >{{ $t('register') }}
-                <div class="ltr:ml-auto rtl:mr-auto rtl:rotate-90 -rotate-90">
-                  <icon-caret-down />
-                </div>
-              </a>
-              <ul
-                class="rounded absolute top-0 ltr:left-[95%] rtl:right-[95%] min-w-[180px] bg-white z-[10] text-dark dark:text-white-dark dark:bg-[#1b2e4b] shadow p-0 py-2 hidden"
-              >
-                <li>
-                  <router-link to="/auth/cover-register" target="_blank">{{ $t('register_cover') }}</router-link>
-                </li>
-                <li>
-                  <router-link to="/auth/boxed-signup" target="_blank">{{ $t('register_boxed') }}</router-link>
-                </li>
-              </ul>
-            </li>
-            <li class="relative">
-              <a href="javascript:;"
-                >{{ $t('password_recovery') }}
-                <div class="ltr:ml-auto rtl:mr-auto rtl:rotate-90 -rotate-90">
-                  <icon-caret-down />
-                </div>
-              </a>
-              <ul
-                class="rounded absolute top-0 ltr:left-[95%] rtl:right-[95%] min-w-[180px] bg-white z-[10] text-dark dark:text-white-dark dark:bg-[#1b2e4b] shadow p-0 py-2 hidden"
-              >
-                <li>
-                  <router-link to="/auth/cover-password-reset" target="_blank">{{ $t('recover_id_cover') }}</router-link>
-                </li>
-                <li>
-                  <router-link to="/auth/boxed-password-reset" target="_blank">{{ $t('recover_id_boxed') }}</router-link>
-                </li>
-              </ul>
-            </li>
-            <li class="relative">
-              <a href="javascript:;"
-                >{{ $t('lockscreen') }}
-                <div class="ltr:ml-auto rtl:mr-auto rtl:rotate-90 -rotate-90">
-                  <icon-caret-down />
-                </div>
-              </a>
-              <ul
-                class="rounded absolute top-0 ltr:left-[95%] rtl:right-[95%] min-w-[180px] bg-white z-[10] text-dark dark:text-white-dark dark:bg-[#1b2e4b] shadow p-0 py-2 hidden"
-              >
-                <li>
-                  <router-link to="/auth/cover-lockscreen" target="_blank">{{ $t('unlock_cover') }}</router-link>
-                </li>
-                <li>
-                  <router-link to="/auth/boxed-lockscreen" target="_blank">{{ $t('unlock_boxed') }}</router-link>
-                </li>
-              </ul>
+              <router-link to="/setting/express">{{ $t('express') }}</router-link>
             </li>
           </ul>
         </li>
-        <li class="menu nav-item relative">
+        <!-- <li class="menu nav-item relative">
           <a href="javascript:;" class="nav-link">
             <div class="flex items-center">
-              <icon-menu-more class="shrink-0" />
-
-              <span class="px-2">{{ $t('more') }}</span>
+              <icon-menu-components class="shrink-0" />
+              <span class="px-2">{{ $t('companyMent') }}</span>
             </div>
             <div class="right_arrow">
-              <icon-caret-down />
             </div>
           </a>
           <ul class="sub-menu">
             <li>
-              <router-link to="/dragndrop">{{ $t('drag_and_drop') }}</router-link>
+              <router-link to="/companyMent/administratorManage">{{ $t('administratorManage') }}</router-link>
             </li>
             <li>
-              <router-link to="/charts">{{ $t('charts') }}</router-link>
+              <router-link to="/setting/roleManage">{{ $t('roleManage') }}</router-link>
             </li>
             <li>
-              <router-link to="/font-icons">{{ $t('font_icons') }}</router-link>
+              <router-link to="/companyMent/branch">{{ $t('branch') }}</router-link>
             </li>
             <li>
-              <router-link to="/widgets">{{ $t('widgets') }}</router-link>
+              <router-link to="/companyMent/configMsg">{{ $t('configMsg') }}</router-link>
             </li>
             <li>
-              <a href="https://vristo.sbthemes.com" target="_blank">{{ $t('documentation') }}</a>
+              <router-link to="/setting/systemLog">{{ $t('systemLog') }}</router-link>
             </li>
           </ul>
         </li> -->
@@ -806,13 +572,13 @@
     class="!rounded-lg"
   >
     <el-form :model="passwordForm" :rules="passwordRules" ref="passwordFormRef" label-width="90px">
-      <el-form-item :label="$t('operator_name')+':'">
+      <el-form-item :label="$t('operator_name') + ':'">
         <el-input v-model="store.state.user.user.username" disabled :placeholder="$t('place')"></el-input>
       </el-form-item>
-      <el-form-item :label="$t('new_password')+':'" prop="password">
+      <el-form-item :label="$t('new_password') + ':'" prop="password">
         <el-input v-model="passwordForm.password" type="password" show-password :placeholder="$t('place')"></el-input>
       </el-form-item>
-      <el-form-item :label="$t('confirm')+$t('admin_password')+':'" prop="conpassword">
+      <el-form-item :label="$t('confirm') + $t('admin_password') + ':'" prop="conpassword">
         <el-input v-model="passwordForm.conpassword" type="password" show-password :placeholder="$t('place')"></el-input>
       </el-form-item>
     </el-form>
@@ -1073,9 +839,9 @@ const passwordForm = ref({
   conpassword: '',
 });
 const passwordRules = ref({
-  password: [{ required: true, message: t('place')+t('admin_password')+'!', trigger: 'blur' }],
+  password: [{ required: true, message: t('place') + t('admin_password') + '!', trigger: 'blur' }],
   conpassword: [
-    { required: true, message: t('place')+t('confirm')+t('admin_password')+'!', trigger: 'blur' },
+    { required: true, message: t('place') + t('confirm') + t('admin_password') + '!', trigger: 'blur' },
     {
       validator: (rule, value, callback) => {
         const password = passwordForm.value.password; // 假设密码存储在 this.form.password 中
@@ -1100,7 +866,7 @@ const submitPasswordForm = () => {
   passwordFormRef.value.validate((valid: boolean) => {
     if (valid) {
       API_Auth.editAdministrator(store.state.user.user.uid, { password: passwordForm.value.password }).then((res) => {
-        ElMessage.success(t('edit_success')+'!');
+        ElMessage.success(t('edit_success') + '!');
         store.dispatch('logoutAction').then(() => {
           const route = router.resolve('/login');
           location.replace(route.href); // 为了重新实例化vue-router对象 避免bug

+ 9 - 4
src/layouts/app-layout.vue

@@ -291,7 +291,7 @@
           </div>
 
           <div class="tags-view-container tabs-box">
-            <!-- 第一种格式 -->
+            <!-- 标签页 -->
             <!-- tabs-box --><!-- :class="'active'" -->
             <scroll-pane class="tags-view-wrapper" ref="scrollPane">
               <router-link
@@ -421,13 +421,17 @@ const contract = () => {
 const expand = () => {
   sidebarShow.value = true;
 };
-
+console.log(store.state.permission);
 /* 监听 */
 const toPath = ref('');
 const toPathList = ref<{ name: any; path: string }[]>([]);
 watch(route, (to) => {
+  console.log(to.path);
+  const secondSlashIndex = to.path.indexOf('/', to.path.indexOf('/') + 1);
+  const valueBeforeSecondSlash = to.path.substring(0, secondSlashIndex);
+  console.log(valueBeforeSecondSlash);
   toPath.value = to.path;
-  // Add path if it doesn't exist
+  //如果路径不存在则添加路径
   if (!toPathList.value.some((item) => item.path === to.path)) {
     toPathList.value.push({ name: to.name || null, path: to.path });
     // Limit to last 10 entries
@@ -461,7 +465,8 @@ const removeTag = (index: number) => {
     toPathList.value.push({ name: '首页', path: '/dashboard' });
   }
 };
-/* 历史标签 */
+/* 侧边栏List */
+const sidebarList = ref([]);
 </script>
 <style>
 #sidebarSwitch {

+ 5 - 1
src/locales/zh.json

@@ -17,6 +17,10 @@
     "orderList":"订单列表",
     "Notify":"通知",
 
+    "procure":"采购",
+    "purchaseOrder":"采购单",
+    "category":"商品分类",
+    
     "overseasWarehouse":"海外仓",
     "overseasWarehouseAuth":"海外仓授权",
     
@@ -56,7 +60,7 @@
     "addInventory":"新增入库",
     "synchronous":"同步",
 
-    "add": "新 增",
+    "add": "新增",
     "edit": "编 辑",
     "view":"查 看",
     "delete":"删 除",

+ 12 - 2
src/router/index.ts

@@ -123,8 +123,8 @@ const asyncRouterMap: RouteRecordRaw[] = [
         name: 'goods',
         children: [
             { path: 'SKUList', component: () => import('@/views/goods/SKUList.vue'), name: 'SKUList', meta: { title: 'SKUList', layout: 'app' } },
-            /*  { path: 'branch', component: () => import('@/views/companyMent/branch.vue'), name: 'branch', meta: { title: 'branch', layout: 'app' } },
-            { path: 'companyInfo', component: () => import('@/views/companyMent/companyInfo.vue'), name: 'companyInfo', meta: { title: 'companyInfo', layout: 'app' } }, */
+            { path: 'category', component: () => import('@/views/goods/category.vue'), name: 'category', meta: { title: 'category', layout: 'app' } },
+            /*{ path: 'companyInfo', component: () => import('@/views/companyMent/companyInfo.vue'), name: 'companyInfo', meta: { title: 'companyInfo', layout: 'app' } }, */
         ]
     },
     {
@@ -137,6 +137,16 @@ const asyncRouterMap: RouteRecordRaw[] = [
             { path: 'companyInfo', component: () => import('@/views/companyMent/companyInfo.vue'), name: 'companyInfo', meta: { title: 'companyInfo', layout: 'app' } }, */
         ]
     },
+    {
+        path: '/procure',
+        redirect: '/procure',
+        name: 'procure',
+        children: [
+            { path: 'purchaseOrder', component: () => import('@/views/procure/purchaseOrder.vue'), name: 'purchaseOrder', meta: { title: 'purchaseOrder', layout: 'app' } },
+            /*  { path: 'branch', component: () => import('@/views/companyMent/branch.vue'), name: 'branch', meta: { title: 'branch', layout: 'app' } },
+            { path: 'companyInfo', component: () => import('@/views/companyMent/companyInfo.vue'), name: 'companyInfo', meta: { title: 'companyInfo', layout: 'app' } }, */
+        ]
+    },
 ];
 
 asyncRouterMap.forEach(route => {

+ 1 - 0
src/stores/index.ts

@@ -9,6 +9,7 @@ import getters from './getters';
 
 // 定义 State 类型
 export interface State {
+    [x: string]: any;
     isDarkMode: boolean;
     mainLayout: string;
     theme: string;

+ 1 - 1
src/stores/modules/permission.js

@@ -12,8 +12,8 @@ const permission = {
   mutations: {
     SET_ROUTERS: (state, routers) => {
       state.addRouters = routers
-      console.log( state.addRouters);
       state.routers = constantRouterMap.concat(routers)
+      console.log(state.routers);
     },
     SET_ROUTERS_ALL: (state, routers) => {
       state.routersAlls = routers

+ 42 - 34
src/views/companyMent/companyInfo.vue

@@ -1,68 +1,68 @@
 <template>
   <div class="bg-white dark:!bg-[#060818]">
     <el-tabs type="border-card" class="bg-gray-100 dark:bg-[#060818]">
-      <el-tab-pane :label="$t('companyDetails')" class="custom-tab-pane">
+      <el-tab-pane v-if="store.state.superMenu == 'compan'" :label="$t('companyDetails')" class="custom-tab-pane">
         <el-form :model="companyForm" :rules="stockRules" ref="companyFormRef" label-width="210px">
           <el-row>
             <el-col :span="24" :md="6">
-              <el-form-item :label="$t('currentPack')+':'" prop="company_package_id">
+              <el-form-item :label="$t('currentPack') + ':'" prop="company_package_id">
                 <el-select v-model="companyForm.company_package_id" clearable placeholder="请选择套餐">
                   <el-option v-for="item in packageList" :key="item.id" :label="item.name" :value="item.id" />
                 </el-select>
               </el-form-item>
             </el-col>
             <el-col :span="24" :md="5">
-              <el-form-item :label="$t('end_use_time')+':'" prop="name">
+              <el-form-item :label="$t('end_use_time') + ':'" prop="name">
                 {{ companyForm.end_use_time }}
               </el-form-item>
             </el-col>
             <el-col :span="24" :md="5">
-              <el-form-item :label="$t('user_num')+':'" prop="name">
+              <el-form-item :label="$t('user_num') + ':'" prop="name">
                 {{ companyForm.user_num }}
               </el-form-item>
             </el-col>
             <el-col :span="24" :md="10">
-              <el-form-item :label="$t('companyName')+':'" prop="name">
+              <el-form-item :label="$t('companyName') + ':'" prop="name">
                 <el-input v-model="companyForm.name" :minlength="2" :maxlength="20" disabled clearable placeholder="请输入公司名称"></el-input>
               </el-form-item>
             </el-col>
             <el-col :span="24" :md="10">
-              <el-form-item :label="$t('credit_code')+':'" prop="credit_code">
+              <el-form-item :label="$t('credit_code') + ':'" prop="credit_code">
                 <el-input v-model="companyForm.credit_code" :minlength="2" :maxlength="20" disabled clearable placeholder="请输入统一社会信用代码"></el-input>
               </el-form-item>
             </el-col>
             <el-col :span="24" :md="10">
-              <el-form-item :label="$t('industry')+':'" prop="industry">
+              <el-form-item :label="$t('industry') + ':'" prop="industry">
                 <el-input v-model="companyForm.industry" :minlength="2" :maxlength="20" disabled clearable placeholder="请输入行业"></el-input>
               </el-form-item>
             </el-col>
             <el-col :span="24" :md="10">
-              <el-form-item :label="$t('company_user_name')+':'" prop="user_name">
+              <el-form-item :label="$t('company_user_name') + ':'" prop="user_name">
                 <el-input v-model="companyForm.user_name" :minlength="2" :maxlength="20" disabled clearable placeholder="请输入联系人"></el-input>
               </el-form-item>
             </el-col>
             <el-col :span="24" :md="10">
-              <el-form-item :label="$t('companyPhone')+':'" prop="phone">
+              <el-form-item :label="$t('companyPhone') + ':'" prop="phone">
                 <el-input v-model="companyForm.phone" :minlength="2" :maxlength="20" disabled clearable placeholder="请输入联系人电话"></el-input>
               </el-form-item>
             </el-col>
             <el-col :span="24" :md="10">
-              <el-form-item :label="$t('companyEmail')+':'" prop="email">
+              <el-form-item :label="$t('companyEmail') + ':'" prop="email">
                 <el-input v-model="companyForm.email" :minlength="2" :maxlength="20" disabled clearable placeholder="请输入邮箱"></el-input>
               </el-form-item>
             </el-col>
             <el-col :span="24" :md="10">
-              <el-form-item :label="$t('postalCode')+':'" prop="postal_code">
+              <el-form-item :label="$t('postalCode') + ':'" prop="postal_code">
                 <el-input v-model="companyForm.postal_code" :minlength="2" :maxlength="20" disabled clearable placeholder="请输入邮箱"></el-input>
               </el-form-item>
             </el-col>
             <el-col :span="24" :md="10">
-              <el-form-item :label="$t('website')+':'" prop="website">
+              <el-form-item :label="$t('website') + ':'" prop="website">
                 <el-input v-model="companyForm.website" :minlength="2" :maxlength="20" disabled clearable placeholder="请输入官网地址"></el-input>
               </el-form-item>
             </el-col>
             <el-col :span="24" :md="10">
-              <el-form-item :label="$t('companyAddress')+':'" prop="">
+              <el-form-item :label="$t('companyAddress') + ':'" prop="">
                 <el-cascader class="w-full" size="default" :options="options" disabled clearable v-model="selectedOptions"></el-cascader>
                 <span>
                   <el-input class="!w-full mt-3" v-model="companyForm.address" disabled placeholder="请输入"></el-input>
@@ -70,7 +70,7 @@
               </el-form-item>
             </el-col>
             <el-col :span="24" :md="10">
-              <el-form-item :label="$t('companyLicense')+':'" prop="license">
+              <el-form-item :label="$t('companyLicense') + ':'" prop="license">
                 <el-upload
                   disabled
                   class="avatar-uploader"
@@ -86,33 +86,35 @@
             </el-col>
           </el-row>
         </el-form>
-        <div class="flex justify-center"><el-button type="primary" @click="submitWarehouseForm">{{$t('save')}}</el-button></div>
+        <div class="flex justify-center">
+          <el-button type="primary" @click="submitWarehouseForm">{{ $t('save') }}</el-button>
+        </div>
       </el-tab-pane>
       <el-tab-pane :label="$t('info')" class="custom-tab-pane">
         <el-form :model="infoForm" :rules="stockRules" ref="infoFormRef" label-width="140px">
           <el-row>
             <el-col :span="24" :md="12" :lg="8">
-              <el-form-item :label="$t('nickname')+':'" prop="nickname">
+              <el-form-item :label="$t('nickname') + ':'" prop="nickname">
                 {{ infoForm.nickname }}
               </el-form-item>
             </el-col>
             <el-col :span="24" :md="12" :lg="8">
-              <el-form-item :label="$t('loginName')+':'" prop="username">
+              <el-form-item :label="$t('loginName') + ':'" prop="username">
                 {{ infoForm.username }}
               </el-form-item>
             </el-col>
             <el-col :span="24" :md="12" :lg="8">
-              <el-form-item :label="$t('phone')+':'" prop="phone">
+              <el-form-item :label="$t('phone') + ':'" prop="phone">
                 {{ infoForm.phone }}
               </el-form-item>
             </el-col>
             <el-col :span="24" :md="12" :lg="8">
-              <el-form-item :label="$t('companyEmail')+':'" prop="email">
+              <el-form-item :label="$t('companyEmail') + ':'" prop="email">
                 {{ infoForm.email }}
               </el-form-item>
             </el-col>
             <el-col :span="24" :md="12" :lg="8">
-              <el-form-item :label="$t('profile')+':'" prop="face">
+              <el-form-item :label="$t('profile') + ':'" prop="face">
                 <el-upload
                   class="avatar-uploader"
                   :action="uploadUrl"
@@ -129,10 +131,10 @@
         </el-form>
 
         <div class="flex justify-center">
-          <el-button type="primary" @click="paySubmit">支付测试</el-button>
-          <el-button type="primary" @click="bindWeChat">{{$t('bindWeChat')}}</el-button
+         <!--  <el-button type="primary" @click="paySubmit">支付测试</el-button> -->
+          <el-button type="primary" @click="bindWeChat">{{ $t('bindWeChat') }}</el-button
           ><!-- v-if="infoForm.openid && infoForm.openid==''" -->
-          <el-button type="primary" @click="submitInfo">{{$t('save')}}</el-button>
+          <el-button type="primary" @click="submitInfo">{{ $t('save') }}</el-button>
         </div>
       </el-tab-pane>
     </el-tabs>
@@ -197,16 +199,19 @@ const beforeAvatarUpload: UploadProps['beforeUpload'] = (rawFile) => {
 /* 支付 */
 let ip = ref<any>(''); // 添加 ip 属性
 const payForm = ref<any>({
-  id: store.state.user.user.company_vo.id,
+  id: '',
   pay_type: 'wx',
   ip: ip.value,
   user_id: store.state.user.user.uid,
 });
 const paySubmit = () => {
-  API_Auth.getPayUrl(payForm.value).then((res) => {
-    console.log(res);
-    callWeChatPay(res);
-  });
+  if (store.state.superMenu == 'compan') {
+    payForm.value.id = store.state.user.user.company_vo.id;
+    API_Auth.getPayUrl(payForm.value).then((res) => {
+      console.log(res);
+      callWeChatPay(res);
+    });
+  }
 };
 
 // 调用微信支付
@@ -313,11 +318,11 @@ const submitWarehouseForm = () => {
       const params = { ...companyForm.value };
       params.province = selectedOptions.value.join(',');
       API_Company.editCompany(companyForm.value.id, params).then(() => {
-        ElMessage.success(t('edit_success')+'!');
+        ElMessage.success(t('edit_success') + '!');
         GET_CompanyList();
       });
     } else {
-      ElMessage.error(t('form_erroe')+'!');
+      ElMessage.error(t('form_erroe') + '!');
       /*    store.dispatch('showMessage', { message: '表单填写有误,请核对!', type: 'error' }); */
       return false;
     }
@@ -326,6 +331,7 @@ const submitWarehouseForm = () => {
 
 const GET_CompanyList = () => {
   loading.value = true;
+
   API_Company.getOne(store.state.user.user.company_vo.id)
     .then((response) => {
       loading.value = false;
@@ -363,12 +369,12 @@ const GET_Info = () => {
 };
 const submitInfo = () => {
   if (infoForm.value.face == undefined) {
-    return ElMessage.error(t('uploadPro')+'!');
+    return ElMessage.error(t('uploadPro') + '!');
   } else if (infoForm.value.face == imgUrl.value) {
-    return ElMessage.error(t('uploadNewPro')+'!');
+    return ElMessage.error(t('uploadNewPro') + '!');
   }
   API_Auth.editAdministrator(store.state.user.user.uid, { face: infoForm.value.face }).then((res) => {
-    ElMessage.success(t('edit_success')+'!');
+    ElMessage.success(t('edit_success') + '!');
     GET_Info();
     store.dispatch('updateUserAction', res);
     /*     location.reload(); */
@@ -376,7 +382,9 @@ const submitInfo = () => {
 };
 
 onMounted(() => {
-  GET_CompanyList();
+  if (store.state.superMenu == 'compan') {
+    GET_CompanyList();
+  }
   GET_PackageList();
   GET_Info();
   getIPAddress();

+ 291 - 41
src/views/goods/SKUList.vue

@@ -4,7 +4,13 @@
       <template #toolbar>
         <div class="inner-toolbar w-11/12 flex justify-between">
           <div class="toolbar-btns">
-            <el-button size="small" v-if="checkPermission(['warehouse:add'])&& store.state.user.user.founder!==1" type="primary" @click="handleAddWarehouse">{{$t('add')}}</el-button>
+            <el-button
+              size="small"
+              v-if="checkPermission(['warehouse:add']) && store.state.user.user.founder !== 1"
+              type="primary"
+              @click="handleAddWarehouse"
+              >{{ $t('add') }}</el-button
+            >
           </div>
           <div class="toolbar-search">
             <en-table-search @search="searchEvent" :placeholder="$t('search_placeholde')" />
@@ -21,15 +27,26 @@
         <el-table-column prop="unit" :label="$t('goods_unit')" />
         <el-table-column prop="image" :label="$t('goods_image')">
           <template #default="scope">
-            <img :src="scope.row.image" style="margin: auto;" width="50px" height="50px" alt="" />
+            <img :src="scope.row.image" style="margin: auto" width="50px" height="50px" alt="" />
           </template>
         </el-table-column>
 
         <el-table-column :label="$t('operate')" fixed="right" width="450">
           <template #default="scope">
-            <el-button size="small" v-if="checkPermission(['warehouse:update'])" @click="handleView(scope.row)">{{$t('view')}}</el-button>
-            <el-button size="small" v-if="checkPermission(['warehouse:update'])&& store.state.user.user.founder!==1" @click="handleEditWarehouse(scope.$index, scope.row)">{{$t('edit')}}</el-button>
-            <el-button type="success" size="small" v-if="checkPermission(['removeAreaType:delete'])&& store.state.user.user.founder!==1" @click="handleDelGoods(scope.row)">{{$t('delete')}}</el-button>
+            <el-button size="small" v-if="checkPermission(['warehouse:update'])" @click="handleView(scope.row)">{{ $t('view') }}</el-button>
+            <el-button
+              size="small"
+              v-if="checkPermission(['warehouse:update']) && store.state.user.user.founder !== 1"
+              @click="handleEditWarehouse(scope.$index, scope.row)"
+              >{{ $t('edit') }}</el-button
+            >
+            <el-button
+              type="success"
+              size="small"
+              v-if="checkPermission(['removeAreaType:delete']) && store.state.user.user.founder !== 1"
+              @click="handleDelGoods(scope.row)"
+              >{{ $t('delete') }}</el-button
+            >
             <!--<el-button size="mini" v-if="checkPermission(['warehouse:update'])" @click="handleRenew(scope.$index, scope.row)">续费</el-button> -->
           </template>
         </el-table-column>
@@ -50,58 +67,266 @@
     </en-table-layout>
 
     <el-dialog
-      :title="skuForm.id ? $t('edit') : $t('add')"
+      :title="skuForm.id ? $t('edit') : $t('add') + '商品'"
       v-model="dialogVisible"
       @open="handleDialogOpen"
       :modal-append-to-body="false"
       :close-on-click-modal="false"
       :close-on-press-escape="false"
-      class="!rounded-lg"
+      width="90%"
+      class="w-11/12 !rounded-lg"
     >
       <el-form :model="skuForm" :rules="stockRules" ref="skuFormRef" label-width="140px">
+        <div class="text-base bg-transparent border-t-0 border-b-0 p-0 pl-3 ml-6 relative mb-5">
+          <span class="pr-2.5">基本信息</span>
+          <div class="absolute left-0 top-0 w-1 h-full bg-[#FB9332] rounded-md"></div>
+        </div>
         <el-row>
-        <!--<el-col :span="10" v-if="!skuForm.id">
-              <el-form-item label="套餐:" prop="company_package_id">
-                <el-select v-model="skuForm.company_package_id" clearable placeholder="请选择套餐">
-                  <el-option v-for="item in packageList" :key="item.id" :label="item.name" :value="item.id" />
-                </el-select>
-              </el-form-item>
-            </el-col> -->
           <el-col :span="10">
-            <el-form-item :label="$t('goods_name')+':'" prop="name">
-              <el-input v-model="skuForm.name" :minlength="2" :maxlength="20" :disabled="disabled" clearable :placeholder="$t('place')+$t('goods_name')"></el-input>
+            <el-form-item :label="$t('库存SKU') + ':'" prop="name">
+              <el-input v-model="skuForm.name" :minlength="2" :maxlength="20" :disabled="disabled" clearable :placeholder="$t('place')"></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col :span="10">
+            <el-form-item :label="$t('本地产品分类') + ':'" prop="name">
+              <el-select v-model="skuForm.company_package_id" clearable placeholder="请选择分类">
+                <el-option v-for="item in productClassList" :key="item.id" :label="item.name" :value="item.id" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="10">
+            <el-form-item :label="$t('标签') + ':'" prop="name">
+              <el-select
+                v-model="skuForm.label"
+                multiple
+                filterable
+                allow-create
+                default-first-option
+                :reserve-keyword="false"
+                placeholder="请输入标签"
+                style="width: 240px"
+              >
+                <el-option v-for="item in labelList" :key="item.value" :label="item.label" :value="item.value" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="10">
+            <el-form-item :label="$t('销售计划') + ':'" prop="name">
+              <span class="mr-2">库存托管</span>
+              <el-switch v-model="skuForm.sale" inline-prompt active-text="开" inactive-text="关" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="10">
+            <el-form-item :label="$t('本地库存总数') + ':'" prop="name">
+              <el-input v-model="skuForm.name" :minlength="2" :maxlength="20" :disabled="disabled" clearable :placeholder="$t('place')"></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col :span="10">
+            <el-form-item :label="$t('可售库存') + ':'" prop="name">
+              <el-input v-model="skuForm.name" :minlength="2" :maxlength="20" :disabled="disabled" clearable :placeholder="$t('place')"></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col :span="10">
+            <el-form-item :label="$t('产品备注') + ':'" prop="name">
+              <el-input v-model="skuForm.name" :minlength="2" :maxlength="20" :disabled="disabled" clearable :placeholder="$t('place')"></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col :span="16">
+            <el-form-item :label="$t('组合产品') + ':'" prop="name">
+              <el-radio-group v-model="skuForm.combination">
+                <el-radio :value="true">是</el-radio>
+                <el-radio :value="false">否</el-radio>
+              </el-radio-group>
+            </el-form-item>
+          </el-col>
+          <el-col :span="24">
+            <el-form-item prop="name">
+              <el-button>选择组合产品</el-button>
+              <el-table :data="combinationList" style="width: 100%">
+                <el-table-column prop="date" label="缩略图" />
+                <el-table-column prop="name" label="sku" />
+                <el-table-column prop="address" label="可售库存" />
+                <el-table-column prop="name" label="组合数量">
+                  <template #default="scope">
+                    <el-input-number v-model="scope.row.num" :disabled="disabled" clearable :placeholder="$t('place')"></el-input-number>
+                  </template>
+                </el-table-column>
+                <el-table-column prop="address" label="产品名称" />
+                <el-table-column prop="address" label="总采购成本" />
+                <el-table-column prop="address" label="操作" />
+              </el-table>
+            </el-form-item>
+          </el-col>
+          <div class="w-full border-b border-gray-300"></div>
+          <div class="text-base bg-transparent border-t-0 border-b-0 p-0 pl-3 ml-6 relative mb-5 mt-5">
+            <span class="pr-2.5">Listing刊登模板</span>
+            <div class="absolute left-0 top-0 w-1 h-full bg-[#FB9332] rounded-md"></div>
+          </div>
+          <el-col :span="24">
+            <el-button class="ml-11">添加刊登模板</el-button>
+          </el-col>
+          <el-col :span="24">
+            <el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick">
+              <el-tab-pane label="亚马逊" name="first">
+                <el-container>
+                  <el-aside width="200px">
+                    <el-menu default-active="1">
+                      <el-menu-item index="1">未命名模板</el-menu-item>
+                      <el-menu-item index="2">美国站,单属性</el-menu-item>
+                    </el-menu>
+                  </el-aside>
+
+                  <el-container>
+                    <el-header>
+                      <el-tabs v-model="activeTab">
+                        <el-tab-pane label="刊登模板" name="1"></el-tab-pane>
+                      </el-tabs>
+                    </el-header>
+
+                    <el-main class="flex justify-between">
+                      <el-form :model="form" label-width="120px">
+                        <el-form-item label="模板名称" required>
+                          <el-input v-model="form.templateName" placeholder="请填写模板名称"></el-input>
+                        </el-form-item>
+
+                        <el-divider></el-divider>
+
+                        <el-form-item label="站点类别">
+                          <el-row>
+                            <el-col :span="12">
+                              <el-form-item label="站点">
+                                <el-select v-model="form.site" placeholder="请选择">
+                                  <el-option label="美国" value="美国"></el-option>
+                                </el-select>
+                              </el-form-item>
+                            </el-col>
+                            <el-col :span="12">
+                              <el-form-item label="刊登类型">
+                                <el-radio-group v-model="form.listingType">
+                                  <el-radio label="单属性"></el-radio>
+                                  <el-radio label="多属性"></el-radio>
+                                </el-radio-group>
+                              </el-form-item>
+                            </el-col>
+                          </el-row>
+                        </el-form-item>
+
+                        <el-form-item label="刊登类别" required>
+                          <el-select v-model="form.category" placeholder="请先选择类别"></el-select>
+                        </el-form-item>
+
+                        <el-divider></el-divider>
+
+                        <el-form-item label="基本信息">
+                          <el-row>
+                            <el-col :span="12">
+                              <el-form-item label="快速填号">
+                                <el-select v-model="form.quickFill" placeholder="请选择"></el-select>
+                              </el-form-item>
+                            </el-col>
+                            <el-col :span="12">
+                              <el-form-item label="亚马逊账号">
+                                <el-select v-model="form.amazonAccount" placeholder="请选择账号"></el-select>
+                              </el-form-item>
+                            </el-col>
+                          </el-row>
+                        </el-form-item>
+
+                        <el-form-item label="标题" required>
+                          <el-input v-model="form.title" placeholder="请输入"></el-input>
+                        </el-form-item>
+
+                        <el-form-item label="平台SKU">
+                          <el-input v-model="form.sku" placeholder="请输入"></el-input>
+                        </el-form-item>
+                      </el-form>
+                      <el-col :span="4">
+                        <!-- 锚点导航 -->
+                        <el-timeline>
+                          <el-timeline-item v-for="(item, index) in anchors" :key="index" :color="item.active ? 'orange' : 'gray'">
+                            <a :href="'#' + item.id" @click="setActiveAnchor(index)">{{ item.label }}</a>
+                          </el-timeline-item>
+                        </el-timeline>
+                      </el-col>
+                    </el-main>
+                  </el-container>
+                </el-container>
+              </el-tab-pane>
+              <!-- <el-tab-pane label="Config" name="second">Config</el-tab-pane> -->
+            </el-tabs>
+          </el-col>
+        </el-row>
+        <!--  <el-row>
+          <el-col :span="10">
+            <el-form-item :label="$t('goods_name') + ':'" prop="name">
+              <el-input
+                v-model="skuForm.name"
+                :minlength="2"
+                :maxlength="20"
+                :disabled="disabled"
+                clearable
+                :placeholder="$t('place') + $t('goods_name')"
+              ></el-input>
             </el-form-item>
           </el-col>
           <el-col :span="10">
-            <el-form-item :label="$t('goods_brand')+':'" prop="brand">
-              <el-input v-model="skuForm.brand" :minlength="2" :maxlength="20" :disabled="disabled" clearable :placeholder="$t('place')+$t('goods_brand')"></el-input>
+            <el-form-item :label="$t('goods_brand') + ':'" prop="brand">
+              <el-input
+                v-model="skuForm.brand"
+                :minlength="2"
+                :maxlength="20"
+                :disabled="disabled"
+                clearable
+                :placeholder="$t('place') + $t('goods_brand')"
+              ></el-input>
             </el-form-item>
           </el-col>
           <el-col :span="10">
-            <el-form-item :label="$t('goods_bar_code')+':'" prop="bar_code">
-              <el-input v-model="skuForm.bar_code" :minlength="2" :maxlength="20" :disabled="disabled" clearable :placeholder="$t('place')+$t('goods_bar_code')"></el-input>
+            <el-form-item :label="$t('goods_bar_code') + ':'" prop="bar_code">
+              <el-input
+                v-model="skuForm.bar_code"
+                :minlength="2"
+                :maxlength="20"
+                :disabled="disabled"
+                clearable
+                :placeholder="$t('place') + $t('goods_bar_code')"
+              ></el-input>
             </el-form-item>
           </el-col>
           <el-col :span="10">
             <el-form-item label="sku:" prop="sku">
-              <el-input v-model="skuForm.sku" :minlength="2" :maxlength="20" :disabled="disabled" clearable :placeholder="$t('place')+'sku'"></el-input>
+              <el-input v-model="skuForm.sku" :minlength="2" :maxlength="20" :disabled="disabled" clearable :placeholder="$t('place') + 'sku'"></el-input>
             </el-form-item>
           </el-col>
           <el-col :span="10">
-            <el-form-item :label="$t('goods_weight')+':'" prop="weight">
-              <el-input v-model="skuForm.weight" :minlength="2" :maxlength="20" :disabled="disabled" clearable :placeholder="$t('place')+$t('goods_weight')"></el-input>
+            <el-form-item :label="$t('goods_weight') + ':'" prop="weight">
+              <el-input
+                v-model="skuForm.weight"
+                :minlength="2"
+                :maxlength="20"
+                :disabled="disabled"
+                clearable
+                :placeholder="$t('place') + $t('goods_weight')"
+              ></el-input>
             </el-form-item>
           </el-col>
           <el-col :span="10">
-            <el-form-item :label="$t('goods_unit')+':'" prop="unit">
-              <el-input v-model="skuForm.unit" :minlength="2" :maxlength="20" :disabled="disabled" clearable :placeholder="$t('place')+$t('goods_unit')"></el-input>
+            <el-form-item :label="$t('goods_unit') + ':'" prop="unit">
+              <el-input
+                v-model="skuForm.unit"
+                :minlength="2"
+                :maxlength="20"
+                :disabled="disabled"
+                clearable
+                :placeholder="$t('place') + $t('goods_unit')"
+              ></el-input>
             </el-form-item>
           </el-col>
           <el-col :span="10">
-            <el-form-item :label="$t('goods_image')+':'" prop="image">
+            <el-form-item :label="$t('goods_image') + ':'" prop="image">
               <el-upload
                 class="avatar-uploader"
-                :action=uploadUrl
+                :action="uploadUrl"
                 :show-file-list="false"
                 :disabled="disabled"
                 :on-success="handleAvatarSuccess"
@@ -112,12 +337,12 @@
               </el-upload>
             </el-form-item>
           </el-col>
-        </el-row>
+        </el-row> -->
       </el-form>
       <template #footer>
         <div class="dialog-footer">
-          <el-button @click="dialogVisible = false">{{$t('cancel')}}</el-button>
-          <el-button type="primary" @click="submitWarehouseForm">{{$t('submit')}}</el-button>
+          <el-button @click="dialogVisible = false">{{ $t('cancel') }}</el-button>
+          <el-button type="primary" @click="submitWarehouseForm">{{ $t('submit') }}</el-button>
         </div>
       </template>
     </el-dialog>
@@ -169,6 +394,22 @@ const beforeAvatarUpload: UploadProps['beforeUpload'] = (rawFile) => {
   }
   return true;
 };
+/* 组合产品 */
+const combinationList = ref([]);
+/* tab标签 */
+const activeName = ref('first');
+const handleClick = () => {};
+
+/* 模板 */
+const activeTab = ref();
+const form = ref<any>({});
+
+/* 锚点 */
+const anchors = ref([
+  { id: 'site-category', label: '站点类别', active: true },
+  { id: 'basic-info', label: '基本信息', active: false },
+  { id: 'product-attributes', label: '产品属性', active: false }
+]);
 
 const store = useStore();
 const tableData = ref<any>({});
@@ -185,14 +426,14 @@ const skuForm = ref<any>({
   unit: '',
 });
 const stockRules = ref<any>({
-  name: [{ required: true, message:t('place') + t('goods_name')+'!', trigger: 'blur' }],
-  brand: [{ required: true, message: t('place') + t('goods_brand')+'!', trigger: 'blur' }],
+  name: [{ required: true, message: t('place') + t('goods_name') + '!', trigger: 'blur' }],
+  brand: [{ required: true, message: t('place') + t('goods_brand') + '!', trigger: 'blur' }],
   snCode: [{ required: true, message: '请输入商品序列号!', trigger: 'blur' }],
-  bar_code: [{ required: true, message:  t('place') + t('goods_bar_code')+'!', trigger: 'blur' }],
-  sku: [{ required: true, message:  t('place') +'sku!', trigger: 'blur' }],
-  weight: [{ required: true, message: t('place') + t('goods_weight')+'!', trigger: 'blur' }],
-  postal_code: [{ required: true, message: t('place') + t('goods_unit')+'!', trigger: 'blur' }],
-  image: [{ required: true, message: t('place') + t('goods_image')+'!', trigger: 'blur' }],
+  bar_code: [{ required: true, message: t('place') + t('goods_bar_code') + '!', trigger: 'blur' }],
+  sku: [{ required: true, message: t('place') + 'sku!', trigger: 'blur' }],
+  weight: [{ required: true, message: t('place') + t('goods_weight') + '!', trigger: 'blur' }],
+  postal_code: [{ required: true, message: t('place') + t('goods_unit') + '!', trigger: 'blur' }],
+  image: [{ required: true, message: t('place') + t('goods_image') + '!', trigger: 'blur' }],
 });
 const selectedOptions = ref<any[]>([]);
 const marketingList = ref<any[]>([]);
@@ -216,6 +457,15 @@ const packageForm = ref<any>({
 let packageId = ref('');
 let companyId = ref('');
 const packageFormRef = ref();
+/* 商品分类列表 */
+const productClassList = ref<any>([]);
+/* 标签列表 */
+const labelList = ref<any>([]);
+  const setActiveAnchor = (index) => {
+  anchors.value.forEach((anchor, i) => {
+    anchor.active = i === index;
+  });
+};
 
 const handleBranch = (index: number, row: any) => {
   router.push({ name: 'branch' });
@@ -284,18 +534,18 @@ const submitWarehouseForm = () => {
       if (id) {
         API_Goods.editProduct(id, params).then(() => {
           dialogVisible.value = false;
-          ElMessage.success(t('edit_success')+'!');
+          ElMessage.success(t('edit_success') + '!');
           GET_GoodsList();
         });
       } else {
         API_Goods.addProduct(params).then(() => {
           dialogVisible.value = false;
-          ElMessage.success(t('add_success')+'!');
+          ElMessage.success(t('add_success') + '!');
           GET_GoodsList();
         });
       }
     } else {
-      ElMessage.error(t('form_erroe')+'!');
+      ElMessage.error(t('form_erroe') + '!');
       /*    store.dispatch('showMessage', { message: '表单填写有误,请核对!', type: 'error' }); */
       return false;
     }
@@ -319,7 +569,7 @@ const handleDelGoods = (row) => {
   ElMessageBox.confirm(t('del_info'), t('prompt'), { type: 'warning' })
     .then(() => {
       API_Goods.delProduct(row.id).then(() => {
-        ElMessage.success(t('del_success')+'!');
+        ElMessage.success(t('del_success') + '!');
         GET_GoodsList();
       });
     })

+ 170 - 0
src/views/goods/category.vue

@@ -0,0 +1,170 @@
+<template>
+  <div class="p-3 bg-white dark:!bg-[#060818]">
+    <div class="toolbar">
+      <div class="inner-toolbar">
+        <div class="toolbar-btns">
+          <span class="pr-2.5">商品类别</span>
+          <el-button size="mini" type="primary" @click="handleAddCategary">新增类别</el-button>
+        </div>
+      </div>
+    </div>
+    <el-tree :data="categorys" node-key="category_id" :expand-on-click-node="false" :default-expanded-keys="expandedKeys" ref="categoryTree">
+      <template #default="{ node, data }">
+        <span class="custom-tree-node" @click="handleSeachShop(data)">
+          <span>{{ data.name }}</span>
+          <span>
+            <el-button
+              type="text"
+              size="mini"
+              :disabled="node.level === 3"
+              icon="el-icon-plus"
+              :title="node.level === 3 ? '类别最多添加三级' : '增加'"
+              @click.stop="handleAddCategary(data)"
+            ></el-button>
+            <el-button type="text" style="color: #f56c6c" size="mini" icon="el-icon-minus" @click.stop="handleDeleteCategory(data)"></el-button>
+            <el-button type="text" size="mini" icon="el-icon-edit" @click.stop="handleEditCategary(data)"></el-button>
+          </span>
+        </span>
+      </template>
+    </el-tree>
+    <!--编辑分类dialog-->
+    <el-dialog
+      :title="categoryForm.name ? '编辑类别' : '添加类别'"
+      v-model="dialogCategoryVisible"
+      width="500px"
+      :close-on-click-modal="false"
+      :close-on-press-escape="false"
+    >
+      <el-form :model="categoryForm" ref="categoryFormRef" label-width="100px">
+        <el-form-item label="上级类别名称" prop="parent_id">
+          <el-cascader
+            v-model="categoryForm.parent_id"
+            ref="cascaderHandle"
+            :options="categorys"
+            :props="{
+              label: 'name',
+              value: 'category_id',
+              emitPath: false,
+              checkStrictly: true,
+            }"
+            @change="handleChange"
+            clearable
+          ></el-cascader>
+        </el-form-item>
+        <el-form-item label="商品类别名称" prop="category_name">
+          <el-input v-model="categoryForm.category_name" :maxlength="12"></el-input>
+        </el-form-item>
+        <el-form-item label="商品类别编号" prop="custom_sn">
+          <el-input v-model="categoryForm.custom_sn"></el-input>
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <span class="dialog-footer">
+          <el-button @click="dialogCategoryVisible = false">取 消</el-button>
+          <el-button type="primary" @click="submitCategoryForm('categoryForm')">确 定</el-button>
+        </span>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+  
+  <script lang="ts" setup>
+import { defineComponent, ref, onMounted, nextTick } from 'vue';
+import { ElMessageBox, FormInstance, ElMessage } from 'element-plus';
+import * as API_Goods from '@/api/goods';
+/* 分类数据 */
+const categorys = ref([]);
+const expandedKeys = ref<string[]>([]);
+/*分类表单*/
+const categoryForm = ref<any>({});
+const dialogCategoryVisible = ref(false);
+/** 添加类别 */
+const handleAddCategary = (category) => {
+  categoryForm.value = {
+    parent_id: category ? category.category_id : 0,
+  };
+  dialogCategoryVisible.value = true;
+};
+/* 删除分类 */
+const categoryTree = ref();
+const handleDeleteCategory = (data: any) => {
+  nextTick(() => {
+    const node = categoryTree.value.getNode(data.category_id);
+    if (!node) {
+      console.error('Node not found for category_id:', data.category_id);
+      return;
+    }
+
+    // 保持父节点展开
+    const parentNode = node.parent;
+    if (parentNode && !expandedKeys.value.includes(parentNode.data.category_id)) {
+      expandedKeys.value.push(parentNode.data.category_id);
+    }
+
+    // 执行删除操作
+    ElMessageBox.confirm('确定要删除这个分类吗?', '提示', { type: 'warning' })
+      .then(() => {
+        API_Goods.deleteCategory(data.category_id).then(() => {
+          ElMessage.success('删除成功!');
+          // 重新设置展开的节点,以防止收缩
+          nextTick(() => {
+            categoryTree.value.store.expandedKeys = expandedKeys.value;
+          });
+        });
+      })
+      .catch(() => {});
+  });
+};
+/*  */
+const params = ref<any>({});
+const handleSeachShop = (data) => {
+  params.value.page_no = 1;
+  params.value.category_id = data.category_id;
+};
+/** 编辑类别  */
+const handleEditCategary = (category) => {
+  categoryForm.value = {
+    parent_id: category.parent_id,
+    category_id: category.category_id,
+    category_name: category.name,
+    custom_sn: category.custom_sn,
+  };
+  dialogCategoryVisible.value = true;
+};
+/* select监听 */
+const cascaderHandle = ref();
+const handleChange = (val) => {
+  categoryForm.value.parent_id = val;
+  cascaderHandle.value.dropDownVisible = false; // 监听值发生变化就关闭它
+};
+/* 提交表单 */
+const submitCategoryForm = (formName) => {
+  /*     const [formName]= */
+  const { category_id } = categoryForm.value;
+  if (!category_id) {
+    API_Goods.addCategory(categoryForm.value).then(() => {
+      dialogCategoryVisible.value = false;
+      ElMessage.success('保存成功!');
+      /* [formName].values.resetFields(); */
+    });
+  } else {
+    API_Goods.editCategory(category_id, categoryForm.value).then((response) => {
+      dialogCategoryVisible.value = false;
+      ElMessage.success('修改成功!');
+      /*    this.$refs[formName].resetFields(); */
+    });
+  }
+};
+</script>
+  
+  <style scoped>
+.inner-toolbar {
+  display: flex;
+  width: 100%;
+  justify-content: space-between;
+  padding: 0 20px;
+}
+.spec-values-select {
+  width: 100%;
+}
+</style>

+ 0 - 1
src/views/order/orderList.vue

@@ -428,7 +428,6 @@ import { useI18n } from 'vue-i18n';
 const { t } = useI18n();
 
 const handleAvatarSuccess: UploadProps['onSuccess'] = (response, uploadFile) => {
-  console.log(response, uploadFile);
   skuForm.value.image = response.url; //URL.createObjectURL(uploadFile.raw!);
 };
 

+ 151 - 0
src/views/procure/purchaseOrder.vue

@@ -0,0 +1,151 @@
+<template>
+  <div class="dark:!bg-[#060818] p-4 bg-white">
+    <div class="search-module">
+      <el-form :model="searchform" ref="searchformRef" inline>
+        <el-form-item>
+          <el-input v-model="searchform.searchQuery" placeholder="采购单号" clearable style="width: 200px" />
+        </el-form-item>
+        <el-form-item>
+          <el-select v-model="searchform.selectedSupplier" placeholder="供应商" style="min-width: 120px; max-width: 200px">
+            <el-option label="供应商1" value="supplier1" />
+            <el-option label="供应商2" value="supplier2" />
+          </el-select>
+        </el-form-item>
+        <el-form-item>
+          <el-select v-model="searchform.selectedWarehouse" placeholder="采购仓库" style="min-width: 120px; max-width: 200px">
+            <el-option label="仓库1" value="warehouse1" />
+            <el-option label="仓库2" value="warehouse2" />
+          </el-select>
+        </el-form-item>
+        <el-form-item>
+          <el-select v-model="searchform.selectedSKU" placeholder="SKU" style="min-width: 120px; max-width: 200px">
+            <el-option label="SKU1" value="sku1" />
+            <el-option label="SKU2" value="sku2" />
+          </el-select>
+        </el-form-item>
+        <el-form-item>
+          <el-date-picker v-model="searchform.dateRange" type="daterange" placeholder="创建日期" style="min-width: 200px; max-width: 300px" />
+        </el-form-item>
+        <el-form-item>
+          <el-select v-model="searchform.selectedStatus" placeholder="付款状态" style="min-width: 120px; max-width: 200px">
+            <el-option label="状态1" value="status1" />
+            <el-option label="状态2" value="status2" />
+          </el-select>
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="handleSearch">搜索</el-button>
+        </el-form-item>
+      </el-form>
+    </div>
+    <el-tabs v-model="activeTab">
+      <el-tab-pane label="全部" name="all"></el-tab-pane>
+      <el-tab-pane label="待审核" name="pending"></el-tab-pane>
+      <el-tab-pane label="待下单" name="toOrder"></el-tab-pane>
+      <el-tab-pane label="待发货" name="toShip"></el-tab-pane>
+      <el-tab-pane label="已完成" name="completed"></el-tab-pane>
+      <el-tab-pane label="已回款" name="paidBack"></el-tab-pane>
+      <el-tab-pane label="已作废" name="canceled"></el-tab-pane>
+    </el-tabs>
+    <en-table-layout :tableData="tableData.records" :toolbar="false" :loading="loading">
+      <template #table-columns>
+        <el-table-column prop="name" :label="$t('order_sn')" />
+        <el-table-column prop="brand" :label="$t('custom')" />
+        <el-table-column prop="bar_code" :label="$t('order_time')" />
+        <el-table-column prop="sku" :label="$t('warechouse_name')" />
+        <el-table-column prop="weight" :label="$t('delivery_method')" />
+        <el-table-column prop="unit" :label="$t('order_type')" />
+        <el-table-column prop="image" :label="$t('user_state')">
+          <template #default="scope">
+            <img :src="scope.row.image" alt="" />
+          </template>
+        </el-table-column>
+        <el-table-column :label="$t('operate')" fixed="right" width="450">
+          <template #default="scope">
+            <el-button size="small" v-if="checkPermission(['warehouse:update'])" @click="handleView(scope.row)">{{ $t('view') }}</el-button>
+            <el-button
+              size="small"
+              v-if="checkPermission(['warehouse:update']) && store.state.user.user.founder !== 1"
+              @click="handleEditWarehouse(scope.$index, scope.row)"
+              >{{ $t('edit') }}</el-button
+            >
+            <el-button
+              type="success"
+              size="small"
+              v-if="checkPermission(['removeAreaType:delete']) && store.state.user.user.founder !== 1"
+              @click="handleDelGoods(scope.row)"
+              >{{ $t('delete') }}</el-button
+            >
+          </template>
+        </el-table-column>
+      </template>
+      <template #pagination>
+        <el-pagination
+          v-if="tableData.records && tableData.records.length"
+          @size-change="handlePageSizeChange"
+          @current-change="handlePageCurrentChange"
+          :current-page="tableData.page_no"
+          :page-sizes="[10, 20, 50, 100]"
+          :page-size="tableData.page_size"
+          layout="total, sizes, prev, pager, next, jumper"
+          :total="tableData.data_total"
+        >
+        </el-pagination>
+      </template>
+    </en-table-layout>
+  </div>
+</template>
+  
+  <script lang="ts" setup>
+import { ref } from 'vue';
+import { ElMessageBox, FormInstance, ElMessage, TabsPaneContext } from 'element-plus';
+import { useStore } from 'vuex';
+
+import { useI18n } from 'vue-i18n';
+
+const { t } = useI18n();
+const store = useStore();
+const activeTab = ref('all');
+const tableData = ref<any>({});
+const loading = ref(false);
+const searchform = ref({
+  searchQuery: '',
+  selectedSupplier: '',
+  selectedWarehouse: '',
+  selectedSKU: '',
+  dateRange: [],
+  selectedStatus: '',
+});
+
+/* 按钮权限 */
+const checkPermission = (permissions: string[]): boolean => {
+  return true;
+};
+
+/* 搜索 */
+const handleSearch = () => {
+  // 处理搜索逻辑
+};
+
+/* 查看 */
+const handleView = (row: any) => {};
+/* 修改 */
+const handleEditWarehouse = (index: any, row: any) => {};
+/* 删除 */
+const handleDelGoods = (row: any) => {};
+/* 每页多少条数据 */
+const handlePageSizeChange = (size: number) => {
+  /*  params.value.page_size = size; */
+};
+/* 翻页 */
+const handlePageCurrentChange = (page: number) => {
+  /* params.value.page_no = page; */
+};
+</script>
+  
+  <style scoped>
+.search-module {
+  display: flex;
+  align-items: center;
+  gap: 10px;
+}
+</style>