dct 9 maanden geleden
bovenliggende
commit
6b50987f95

+ 2 - 1
.env.serve

@@ -3,7 +3,8 @@ NODE_ENV=development
 VUE_APP_CURRENTMODE=serve
 
 #VUE_APP_BASEURL=https://kaung.cn:20005/
-VUE_APP_BASEURL=http://kaung.cn:7001
+# VUE_APP_BASEURL=http://kaung.cn:7001
+VUE_APP_BASEURL=https://ljyx.hhtrip.com.cn
 #VUE_APP_BASEURL=https://localhost:5002/
 #VUE_APP_BASEURL=https://localhost:5200/
 #VUE_APP_BASEURL=https://localhost:7209/

BIN
public/证件号导入模板.xlsx


+ 108 - 125
src/api/basic.js

@@ -1,187 +1,170 @@
-import util from '@/utils/util'
-import request from '@/utils/request'
-
+import util from '@/utils/util';
+import request from '@/utils/request';
 
 export function fetchDictTree(category) {
-    return request({
-        url: '/BaseDict/Tree?category=' + (category || 'dict'),
-        method: 'get'
-    });
+  return request({
+    url: '/BaseDict/Tree?category=' + (category || 'dict'),
+    method: 'get',
+  });
 }
 
 export function submitDict(data) {
-    return request({
-        url: '/BaseDict/' + (data.id || ''),
-        method: data.id ? 'put' : 'post',
-        data: data
-    });
+  return request({
+    url: '/BaseDict/' + (data.id || ''),
+    method: data.id ? 'put' : 'post',
+    data: data,
+  });
 }
 
-
 export function fetchDictPager(params) {
-    return request({
-        url: '/BaseDict/Search?r=' + Math.random(),
-        method: 'post',
-        data: params
-    })
+  return request({
+    url: '/BaseDict/Search?r=' + Math.random(),
+    method: 'post',
+    data: params,
+  });
 }
 
 export function delDict(dataID) {
-    return request({
-        url: '/BaseDict/' + (dataID || ''),
-        method: 'delete'
-    });
+  return request({
+    url: '/BaseDict/' + (dataID || ''),
+    method: 'delete',
+  });
 }
 
-
 /**
  * 字典项
  */
 export function dicts(category, code) {
-    return request({
-        url: '/BaseDict/List?v=' + util.getVersion(),
-        params: {
-            category: category || '',
-            code: code || ''
-        },
-        method: 'get',
-        cache: 60 * 60 * 24 * 7 //7天的缓存
-    }).then((res) => {
-        var options = [];
-        res.data.forEach(function (item) {
-            options.push({
-                "name": item.name,
-                "value": item.value,
-                "code": item.code,
-                "category": item.category,
-                "attribute": item.attribute,
-                "id": item.id
-            });
-        });
-        return options;
+  return request({
+    url: '/BaseDict/List?v=' + util.getVersion(),
+    params: {
+      category: category || '',
+      code: code || '',
+    },
+    method: 'get',
+    cache: 60 * 60 * 24 * 7, //7天的缓存
+  }).then((res) => {
+    var options = [];
+    res.data.forEach(function (item) {
+      options.push({
+        name: item.name,
+        value: item.value,
+        code: item.code,
+        category: item.category,
+        attribute: item.attribute,
+        id: item.id,
+      });
     });
+    return options;
+  });
 }
 
-
-
-
 export function fetchFileList(dataID, fileCode) {
-    return request({
-        url: '/BaseUploader/Files?dataID=' + (dataID || '') + '&fileCode=' + (fileCode || ''),
-        method: 'get'
-    });
+  return request({
+    url: '/BaseUploader/Files?dataID=' + (dataID || '') + '&fileCode=' + (fileCode || ''),
+    method: 'get',
+  });
 }
 export function fetchFileDetail(id) {
-    return request({
-        url: '/BaseUploader/' + id,
-        method: 'get'
-    });
+  return request({
+    url: '/BaseUploader/' + id,
+    method: 'get',
+  });
 }
 
 export function delFile(dataID) {
-    if (dataID)
-        return request({
-            url: '/BaseUploader/' + (dataID || ''),
-            method: 'delete'
-        });
+  if (dataID)
+    return request({
+      url: '/BaseUploader/' + (dataID || ''),
+      method: 'delete',
+    });
 }
 
-
 export function getCompanyTree() {
-    return fetchCompanyTree(0);//不加缓存
+  return fetchCompanyTree(0); //不加缓存
 }
 
 export function fetchCompanyTree(cache) {
-    var body = {
-        url: '/BaseCompany/Tree?v=' + util.getVersion(),
-        method: 'get'
-    };
-    let timer = cache && 60 * 60 * 24 * 7;
-    if (timer > 0)
-        body.cache = timer; //7天的缓存
+  var body = {
+    url: '/BaseCompany/Tree?v=' + util.getVersion(),
+    method: 'get',
+  };
+  let timer = cache && 60 * 60 * 24 * 7;
+  if (timer > 0) body.cache = timer; //7天的缓存
 
-    return request(body);
+  return request(body);
 }
 
 export function submitCompany(data) {
-    return request({
-        url: '/BaseCompany/' + (data.id || ''),
-        method: data.id ? 'put' : 'post',
-        data: data
-    });
+  return request({
+    url: '/BaseCompany/' + (data.id || ''),
+    method: data.id ? 'put' : 'post',
+    data: data,
+  });
 }
 
-
 export function delCompany(dataID) {
-    return request({
-        url: '/BaseCompany/' + (dataID || ''),
-        method: 'delete'
-    });
+  return request({
+    url: '/BaseCompany/' + (dataID || ''),
+    method: 'delete',
+  });
 }
 
-
-
-
 export function getDepartmentTree(companyId) {
-    return fetchDepartmentTree(companyId, 0);//不加缓存
+  return fetchDepartmentTree(companyId, 0); //不加缓存
 }
 export function fetchDepartmentTree(companyId, cache) {
-    var body = {
-        url: '/BaseDepartment/Tree?CompanyId=' + companyId + '&&v=' + util.getVersion(),
-        method: 'get'
-    };
-    let timer = cache && 60 * 60 * 24 * 7;
-    if (timer > 0)
-        body.cache = timer; //7天的缓存
+  var body = {
+    url: '/BaseDepartment/Tree?CompanyId=' + companyId + '&&v=' + util.getVersion(),
+    method: 'get',
+  };
+  let timer = cache && 60 * 60 * 24 * 7;
+  if (timer > 0) body.cache = timer; //7天的缓存
 
-    return request(body);
+  return request(body);
 }
 
 export function submitDepartment(data) {
-    return request({
-        url: '/BaseDepartment/' + (data.id || ''),
-        method: data.id ? 'put' : 'post',
-        data: data
-    });
+  return request({
+    url: '/BaseDepartment/' + (data.id || ''),
+    method: data.id ? 'put' : 'post',
+    data: data,
+  });
 }
 
-
 export function delDepartment(dataID) {
-    return request({
-        url: '/BaseDepartment/' + (dataID || ''),
-        method: 'delete'
-    });
+  return request({
+    url: '/BaseDepartment/' + (dataID || ''),
+    method: 'delete',
+  });
 }
 
-
-
 export function fetchMenus(category) {
-    return request({
-        url: '/BaseModule/TreeData?category=' + (category || '') + '&v=' + util.getVersion(),
-        params: {},
-        method: 'get'
-    }).then((res) => {
-        return res.data;
-    });
+  return request({
+    url: '/BaseModule/TreeData?category=' + (category || '') + '&v=' + util.getVersion(),
+    params: {},
+    method: 'get',
+  }).then((res) => {
+    return res.data;
+  });
 }
 
-
 export function fetchMenuDetail(id) {
-    return request({
-        url: '/BaseModule/' + id,
-        method: 'get'
-    });
+  return request({
+    url: '/BaseModule/' + id,
+    method: 'get',
+  });
 }
 export function submitMenu(data) {
-    return request({
-        url: '/BaseModule/' + (data.id || ''),
-        method: data.id ? 'put' : 'post',
-        data: data
-    });
+  return request({
+    url: '/BaseModule/' + (data.id || ''),
+    method: data.id ? 'put' : 'post',
+    data: data,
+  });
 }
 export function delMenu(dataID) {
-    return request({
-        url: '/BaseModule/' + (dataID || ''),
-        method: 'delete'
-    });
+  return request({
+    url: '/BaseModule/' + (dataID || ''),
+    method: 'delete',
+  });
 }

+ 6 - 0
src/api/order.js

@@ -16,6 +16,12 @@ export function delOrder(id) {
   });
 }
 
+export function getOrderNo() {
+  return request({
+    url: '/TourOrder/OrderNo',
+    method: 'post'
+  });
+}
 export function createOrder(data) {
   const id = data.id;
   return request({

+ 10 - 0
src/api/pay.js

@@ -0,0 +1,10 @@
+import util from '@/utils/util';
+import request from '@/utils/request';
+
+export function getPayParams (orderID, payType) {
+  return request({
+    url: `/TourOrder/${orderID}/PayParams`,
+    method: 'post',
+    data: { paymentMethod: payType || 'Online' },
+  });
+}

+ 7 - 0
src/api/sys.js

@@ -78,6 +78,13 @@ export function fetchRoles(params) {
   });
 }
 
+export function getRole(id) {
+  return request({
+    url: '/BaseRole/' + id,
+    method: 'get'
+  });
+}
+
 
 export function delRoles(id) {
   return request({

+ 15 - 0
src/constant/index.js

@@ -4,3 +4,18 @@ export const ProductTypes = {
   'Restaurant': '餐饮',
   'Other': '其他'
 }
+
+
+export const FileTypeMap = {
+  'application/pdf': 'pdf',
+  'image/jpeg': 'jpg',
+  'image/jpg': 'jpg',
+  'image/png': 'png',
+  'image/gif': 'gif',
+  'application/msword': 'doc',
+  'application/vnd.openxmlformats-officedocument.wordprocessingml.document': 'docx',
+  'application/vnd.ms-excel': 'xls',
+  'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': 'excel',
+  'application/vnd.ms-powerpoint': 'ppt',
+  'application/vnd.openxmlformats-officedocument.presentationml.presentation': 'pptx',
+}

+ 23 - 14
src/layout/components/menuTree.vue

@@ -1,26 +1,26 @@
 <template>
   <div class="menu-list">
-    <el-sub-menu index="/travelAgency/">
+    <el-sub-menu index="/travelAgency/" v-if="isAdmin">
       <template #title>
         <span>旅行社</span>
       </template>
-      <el-menu-item index="/travelAgency/list">
+      <el-menu-item index="/travelAgency/list" v-if="isAdmin">
         <span>旅行社管理</span>
       </el-menu-item>
     </el-sub-menu>
-    <el-sub-menu index="/product/">
+    <el-sub-menu index="/product/" v-if="isAdmin">
       <template #title>
         <span>产品</span>
       </template>
-      <el-menu-item index="/product/list">
-        <span>产品管理</span>
-      </el-menu-item>
       <el-menu-item index="/product/category">
         <span>产品分类</span>
       </el-menu-item>
-      <el-menu-item index="/product/tag">
-        <span>产品标签</span>
+      <el-menu-item index="/product/list">
+        <span>产品管理</span>
       </el-menu-item>
+      <!-- <el-menu-item index="/product/tag">
+        <span>产品标签</span>
+      </el-menu-item> -->
     </el-sub-menu>
     <el-sub-menu index="/order/">
       <template #title>
@@ -29,17 +29,14 @@
       <el-menu-item index="/order/list">
         <span>订单管理</span>
       </el-menu-item>
-      <el-menu-item index="/order/review">
+      <el-menu-item index="/order/review" v-if="isAdmin">
         <span>订单审核</span>
       </el-menu-item>
     </el-sub-menu>
-    <el-sub-menu index="/sys/">
+    <el-sub-menu index="/sys/" v-if="isAdmin">
       <template #title>
         <span>系统</span>
       </template>
-      <el-menu-item index="/sys/role">
-        <span>角色管理</span>
-      </el-menu-item>
       <el-menu-item index="/sys/company">
         <span>公司管理</span>
       </el-menu-item>
@@ -49,6 +46,12 @@
       <el-menu-item index="/sys/user">
         <span>用户管理</span>
       </el-menu-item>
+      <el-menu-item index="/sys/role">
+        <span>角色管理</span>
+      </el-menu-item>
+      <!-- <el-menu-item index="/sys/menu">
+        <span>菜单管理</span>
+      </el-menu-item> -->
       <!-- <el-menu-item index="/sys/userReset">
         <span>用户重置</span>
       </el-menu-item>
@@ -72,9 +75,15 @@
   </div>
 </template>
 <script>
+import store from '@/store';
 export default {
   name: 'MenuTree',
-  props: ['menuData']
+  props: ['menuData'],
+  computed: {
+    isAdmin() {
+      return store.getters.getUserInfo?.roles?.includes('Admin');
+    }
+  },
 }
 </script>
 <style>

+ 58 - 58
src/layout/index.vue

@@ -57,14 +57,15 @@
               </el-text>
               <template #dropdown>
                 <el-dropdown-menu>
-                  <el-dropdown-item v-for="item in sidemenus">
+                  <el-dropdown-item v-for="item in sidemenus" :key="item.id">
                     <a :href="item.value" target="_blank">{{ item.name }}</a>
                   </el-dropdown-item>
                 </el-dropdown-menu>
               </template>
             </el-dropdown>
             <!-- <el-text> | </el-text> -->
-            <el-badge :value="unreadMsgCount > 0 ? unreadMsgCount : ''" :hidden="unreadMsgCount === 0" :max="99" class="message-badge" @click="goToMessage">
+            <el-badge :value="unreadMsgCount > 0 ? unreadMsgCount : ''" :hidden="unreadMsgCount === 0" :max="99"
+              class="message-badge" @click="goToMessage">
               <el-icon>
                 <Bell />
               </el-icon>
@@ -96,63 +97,63 @@
       </el-main>
       <!-- <el-footer>Footer</el-footer> -->
     </el-container>
-  </el-container>
-
-  <div class="dialog">
-    <resetPwdDialog :visible="resetDialogVisible"></resetPwdDialog>
-  </div>
-
-
-  <static-dialog ref="userDialog" class="dialog" title="个人设置" :okVisible="false">
-    <el-form :model="forms" ref="forms" label-width="90px">
-      <el-row :gutter="10">
-        <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
-          <el-form-item label="公司" prop="companyName">
-            <el-input v-model="forms.companyName" autocomplete="off" disabled> </el-input>
-          </el-form-item>
-        </el-col>
-        <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
-          <el-form-item label="部门" prop="departmentName">
-            <el-input v-model="forms.departmentName" autocomplete="off" disabled> </el-input>
-          </el-form-item>
-        </el-col>
-        <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
-          <el-form-item label="账户" prop="account">
-            <el-input v-model="forms.account" autocomplete="off" disabled></el-input>
-          </el-form-item>
-        </el-col>
-        <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
-          <el-form-item label="姓名" prop="realName">
-            <el-input v-model="forms.realName" autocomplete="off" disabled></el-input>
-          </el-form-item>
-        </el-col>
-        <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
-          <el-form-item label="性别" prop="gender" class="gender" disabled>
-            <el-radio v-model="forms.gender" label="男">男</el-radio>
-            <el-radio v-model="forms.gender" label="女">女</el-radio>
-            <el-radio v-model="forms.gender" label="无">无</el-radio>
-            <!-- <el-radio-group v-model="forms.gender" disabled>
+    <div class="dialog">
+      <resetPwdDialog ref="resetPwdRef" :visible="resetDialogVisible"></resetPwdDialog>
+    </div>
+
+
+    <static-dialog ref="userDialog" class="dialog" title="个人设置" :okVisible="false">
+      <el-form :model="forms" ref="forms" label-width="90px">
+        <el-row :gutter="10">
+          <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+            <el-form-item label="公司" prop="companyName">
+              <el-input v-model="forms.companyName" autocomplete="off" disabled> </el-input>
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+            <el-form-item label="部门" prop="departmentName">
+              <el-input v-model="forms.departmentName" autocomplete="off" disabled> </el-input>
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+            <el-form-item label="账户" prop="account">
+              <el-input v-model="forms.account" autocomplete="off" disabled></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+            <el-form-item label="姓名" prop="realName">
+              <el-input v-model="forms.realName" autocomplete="off" disabled></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+            <el-form-item label="性别" prop="gender" class="gender" disabled>
+              <el-radio v-model="forms.gender" label="男">男</el-radio>
+              <el-radio v-model="forms.gender" label="女">女</el-radio>
+              <el-radio v-model="forms.gender" label="无">无</el-radio>
+              <!-- <el-radio-group v-model="forms.gender" disabled>
               <el-radio label="男" />
               <el-radio label="女" />
               <el-radio label="无" />
             </el-radio-group>-->
-          </el-form-item>
-        </el-col>
-        <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
-          <el-form-item label="手机" prop="mobile">
-            <el-input v-model="forms.mobile" autocomplete="off" disabled></el-input>
-          </el-form-item>
-        </el-col>
-        <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
-          <el-form-item label="生日" prop="birthday">
-            <el-date-picker v-model="forms.birthday" type="date" placeholder="选择生日" format="YYYY-MM-DD"
-              :editable="false" disabled>
-            </el-date-picker>
-          </el-form-item>
-        </el-col>
-      </el-row>
-    </el-form>
-  </static-dialog>
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+            <el-form-item label="手机" prop="mobile">
+              <el-input v-model="forms.mobile" autocomplete="off" disabled></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+            <el-form-item label="生日" prop="birthday">
+              <el-date-picker v-model="forms.birthday" type="date" placeholder="选择生日" format="YYYY-MM-DD"
+                :editable="false" disabled>
+              </el-date-picker>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+    </static-dialog>
+  </el-container>
+
 </template>
 
 <script>
@@ -160,7 +161,6 @@ import store from "@/store";
 import StaticDialog from "@/components/static-dialog.vue";
 import AppAside from "./components/aside";
 import resetPwdDialog from "@/views/sys/user/reset.vue";
-
 import { currentMenus, webSetting, currentUser } from "@/api/sys";
 import { logout } from "@/api/login";
 
@@ -275,7 +275,7 @@ export default {
       }
     },
     resetEvent() {
-      this.resetDialogVisible = true;
+      this.$refs.resetPwdRef.open();
     },
     logoutEvent() {
       logout();
@@ -313,7 +313,7 @@ export default {
     // 获取未读消息数量
     getUnreadMessageCount() {
       this.$kaung.fetch({
-        url: '/BaseUser/Dashboard',method: 'get',loading: false,cache: 5,//5s
+        url: '/BaseUser/Dashboard', method: 'get', loading: false, cache: 5,//5s
       }).then((res) => {
         this.unreadMsgCount = res.data.unreadCount || 0;
       }).catch((err) => {

+ 5 - 0
src/router/index.js

@@ -128,6 +128,11 @@ const routes = [
         name: 'MessageDetail',
         component: () => import('@/views/sys/message/detail'),
       },
+      {
+        path: 'menu',
+        name: 'Menu',
+        component: () => import('@/views/sys/menu/index'),
+      },
     ],
   },
   {

+ 2 - 2
src/utils/kaung.js

@@ -95,7 +95,7 @@ var kaung = {
 
   companys() {
     return request({
-      url: '/BaseCompany/Tree?v=' + util.getVersion(),
+      url: '/BaseCompany/Tree',
       method: 'get',
       cache: (60 * 60 * 24 * 5)
     }).then((res) => {
@@ -104,7 +104,7 @@ var kaung = {
   },
   departments(companyId) {
     return request({
-      url: '/BaseDepartment/Tree?CompanyId=' + companyId + '&v=' + util.getVersion(),
+      url: '/BaseDepartment/Tree?CompanyId=' + companyId,
       method: 'get',
       cache: (60 * 60 * 24 * 5)
     }).then((res) => {

+ 1 - 1
src/utils/request.js

@@ -38,7 +38,7 @@ request.interceptors.request.use(
       // if (queryDialogOverlay && queryDialogOverlay.style.display != "none")
       //     loadTarget = ".load-dialog .el-dialog";
       if (config.loading == undefined || config.loading) {
-        showFullScreenLoading();
+        // showFullScreenLoading();
       }
     }
 

+ 433 - 76
src/views/order/index.vue

@@ -7,14 +7,46 @@
       </el-breadcrumb>
     </template>
     <el-form :model="forms" ref="forms" label-width="70px" class="search-form">
-      <el-row>
-        <el-form-item label="关键词" prop="keyword">
+      <el-row style="align-items: center">
+        <el-form-item label="关键词" prop="keyword" style="margin: 0 10px">
           <el-col>
-            <el-input v-model="forms.keyword" prefix-icon="Search"></el-input>
+            <el-input v-model="forms.keyword" clearable prefix-icon="Search"></el-input>
           </el-col>
         </el-form-item>
+        <el-form-item label="订单状态" prop="status" style="margin: 0 10px">
+          <el-select v-model="forms.status" :empty-values="[null, undefined]" :value-on-clear="null" clearable
+            style="width: 100px">
+            <el-option label="全部" value=""></el-option>
+            <el-option label="草稿" value="Draft"></el-option>
+            <el-option label="已提交" value="Submitted"></el-option>
+            <el-option label="已审核" value="Approved"></el-option>
+            <el-option label="已支付" value="Paid"></el-option>
+            <el-option label="已确认" value="Confirmed"></el-option>
+            <el-option label="处理中" value="Processing"></el-option>
+            <el-option label="已完成" value="Completed"></el-option>
+            <el-option label="已取消" value="Cancelled"></el-option>
+            <el-option label="已驳回" value="Rejected"></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="审核状态" prop="status" style="margin: 0 10px">
+          <el-select v-model="forms.auditStatus" :empty-values="[null, undefined]" :value-on-clear="null" clearable
+            style="width: 100px">
+            <el-option label="全部" value=""></el-option>
+            <el-option label="待审核" value="Pending"></el-option>
+            <el-option label="审核通过" value="Approved"></el-option>
+            <el-option label="审核驳回" value="Rejected"></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="支付状态" prop="paymentStatus" style="margin: 0 10px">
+          <el-select v-model="forms.paymentStatus" :empty-values="[null, undefined]" :value-on-clear="null" clearable
+            style="width: 100px">
+            <el-option label="全部" value=""></el-option>
+            <el-option label="待支付" value="Pending"></el-option>
+            <el-option label="已支付" value="Paid"></el-option>
+          </el-select>
+        </el-form-item>
         <el-form-item label="" label-width="20px">
-          <el-button type="primary" icon="search" @click="submit('forms')">
+          <el-button type="primary" icon="search" @click="searchOrderList">
             搜索
           </el-button>
         </el-form-item>
@@ -40,7 +72,7 @@
         <template #default="scope">
           <div>开始日期: {{ scope.row.travelStartDate }}</div>
           <div>结束日期: {{ scope.row.travelEndDate }}</div>
-          <div>共: <el-tag size="small">{{ scope.row.travelDays }}天</el-tag></div>
+          <div>共: <el-tag size="small">{{ scope.row.travelDays + 1 }}天</el-tag></div>
         </template>
       </el-table-column>
       <el-table-column prop="touristCount" label="人数" width="80" align="center"></el-table-column>
@@ -83,10 +115,13 @@
         <template #default="scope">
           <!-- <el-button type="primary" link size="small" @click="edit(scope.row)">编辑</el-button> -->
           <!-- <el-button type="success" link size="small" @click="audit(scope.row)">审核</el-button> -->
-          <el-button type="warning" link size="small" @click="payment(scope.row)">收款</el-button>
+          <el-button type="info" link size="small" @click="attachment(scope.row)">附件</el-button>
+          <el-button type="warning" v-if="userAccountId === 'testuser'" link size="small"
+            @click="payment(scope.row)">收款</el-button>
           <el-button type="info" link size="small" @click="editSchedule(scope.row)">行程</el-button>
           <el-button type="primary" link size="small" @click="editTourists(scope.row)">游客</el-button>
-          <el-button type="danger" link size="small" @click="del(scope.row)">删除</el-button>
+          <el-button v-if="scope.row.status === 'Submitted'" type="danger" link size="small"
+            @click="del(scope.row)">删除</el-button>
         </template>
       </el-table-column>
     </el-table>
@@ -104,7 +139,8 @@
               <el-row :gutter="10">
                 <el-col :span="24">
                   <el-form-item label="旅行社" prop="agencyID">
-                    <el-select v-model="formData.agencyID" filterable @change="handleAgencyChange">
+                    <el-select v-model="formData.agencyID" :disabled="!!userAgencyId" filterable
+                      @change="handleAgencyChange">
                       <el-option v-for="item in agencyOptions" :key="item.id" :label="item.agencyName" :value="item.id">
                       </el-option>
                     </el-select>
@@ -215,7 +251,7 @@
                   </el-table-column>
                   <el-table-column label="操作" width="100" align="center">
                     <template #default="scope">
-                      <el-button type="primary" link size="small" @click="editProductItem(scope.row)">编辑</el-button>
+                      <!-- <el-button type="primary" link size="small" @click="editProductItem(scope.row)">编辑</el-button> -->
                       <el-button type="danger" link size="small" @click="delProductItem(scope.$index)">删除</el-button>
                     </template>
                   </el-table-column>
@@ -241,16 +277,19 @@
               </div>
             </el-collapse-item>
 
-            <el-collapse-item title="游客信息" name="tourists">
+            <el-collapse-item title="领队/游客信息" name="tourists">
               <div>
                 <div class="product-toolbar" style="margin-bottom:10px;">
-                  <el-button type="primary" size="small" @click="addTouristInfo">
+                  <el-button type="primary" size="small" @click="addTouristItem(true)">
+                    新增领队
+                  </el-button>
+                  <el-button type="primary" size="small" @click="addTouristItem(false)">
                     新增游客
                   </el-button>
-                  <el-button type="danger" size="small" v-if="formData.tourists && formData.tourists.length"
+                  <!-- <el-button type="danger" size="small" v-if="formData.tourists && formData.tourists.length"
                     @click="formData.tourists = []">
                     清空游客
-                  </el-button>
+                  </el-button> -->
                 </div>
 
                 <el-table :data="formData.tourists || []" border size="small" style="width:100%">
@@ -401,6 +440,43 @@
                 </el-col>
               </el-row>
             </el-collapse-item>
+            <el-collapse-item title="附件" name="attachments">
+              <el-row :gutter="10" style="margin-bottom: 10px">
+                <el-col :span="24">
+                  <el-button type="primary" size="small" @click="downloadTemplate">下载模板</el-button>
+                </el-col>
+              </el-row>
+              <el-row :gutter="10">
+                <el-col :span="24">
+                  <el-upload ref="orderUploadRef" action="/api/BaseUploader/Basic" :show-file-list="false"
+                    :data="uploadParams" :headers="headers" accept=".xls,.xlsx" :limit="10" :on-success="uploadSuccess"
+                    :file-list="fileList" :on-error="uploadError" :on-remove="removeFile" :before-upload="beforeUpload"
+                    @on-preview="downloadFile">
+                    <el-button type="primary" size="small">上传<i class="el-icon-plus"></i></el-button>
+                  </el-upload>
+
+                  <div class="file-list">
+                    <el-row v-if="fileList && fileList.length" :gutter="10" style="align-items:center;">
+                      <el-col v-for="file in fileList" :key="file.id || file.raw?.uid" :span="24"
+                        style="display:flex;align-items:center;justify-content:space-between;margin-bottom:6px;">
+                        <div style="flex:1;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;">
+                          <a href="javascript:;" @click.prevent="downloadFile(file)" style="color:#409EFF;">
+                            {{ file.name }}
+                          </a>
+                          <span style="color:#999;margin-left:8px;">{{ file.url ? '' : '(本地文件)' }}</span>
+                        </div>
+                        <div style="margin-left:12px;white-space:nowrap;">
+                          <el-button type="text" size="small" @click="downloadFile(file)">下载</el-button>
+                          <el-button type="danger" size="small" @click="removeFile(file)">删除</el-button>
+                        </div>
+                      </el-col>
+                    </el-row>
+
+                    <div v-else style="text-align:center;color:#999;padding:12px;">暂无附件</div>
+                  </div>
+                </el-col>
+              </el-row>
+            </el-collapse-item>
           </el-collapse>
         </el-scrollbar>
       </el-form>
@@ -414,10 +490,11 @@
       </template>
     </el-dialog>
 
-    <el-dialog title="行程信息维护" width="700px" v-model="scheduleDialogVisible" destroy-on-close :before-close="currentOrderId = ''">
-      <div class="schedule-toolbar" style="margin-bottom: 10px">
+    <el-dialog title="行程信息" width="700px" v-model="scheduleDialogVisible" destroy-on-close
+      :before-close="currentOrderId = ''">
+      <!-- <div class="schedule-toolbar" style="margin-bottom: 10px">
         <el-button type="primary" size="small" @click="addSchedule">新增行程</el-button>
-      </div>
+      </div> -->
 
       <el-table :data="scheduleList" border style="width: 100%" size="small">
         <el-table-column type="index" label="序号" width="50" align="center" />
@@ -428,12 +505,12 @@
           </template>
         </el-table-column>
         <el-table-column prop="title" label="标题" />
-        <el-table-column label="操作" width="120" align="center">
+        <!-- <el-table-column label="操作" width="120" align="center">
           <template #default="scope">
             <el-button type="primary" link size="small" @click="editScheduleItem(scope.row)">编辑</el-button>
             <el-button type="danger" link size="small" @click="delScheduleItem(scope.$index)">删除</el-button>
           </template>
-        </el-table-column>
+        </el-table-column> -->
       </el-table>
     </el-dialog>
 
@@ -460,10 +537,11 @@
       </template>
     </el-dialog>
 
-    <el-dialog title="游客信息维护" width="900px" v-model="touristsDialogVisible" destroy-on-close :before-close="currentOrderId = ''">
-      <div class="tourists-toolbar" style="margin-bottom: 10px;">
-        <el-button type="primary" size="small" @click="addTouristInfo">新增游客</el-button>
-      </div>
+    <el-dialog title="游客信息" width="900px" v-model="touristsDialogVisible" destroy-on-close
+      :before-close="currentOrderId = ''">
+      <!-- <div class="tourists-toolbar" style="margin-bottom: 10px;">
+        <el-button type="primary" size="small" @click="addTouristItem">新增游客</el-button>
+      </div> -->
 
       <el-table :data="touristsList" border style="width: 100%" size="small">
         <el-table-column type="index" label="序号" width="50" align="center" />
@@ -489,12 +567,12 @@
             <el-tag v-else type="info">否</el-tag>
           </template>
         </el-table-column>
-        <el-table-column label="操作" width="120" align="center">
+        <!-- <el-table-column label="操作" width="120" align="center">
           <template #default="scope">
             <el-button type="primary" link size="small" @click="editTouristItem(scope.row)">编辑</el-button>
             <el-button type="danger" link size="small" @click="delTouristItem(scope.$index)">删除</el-button>
           </template>
-        </el-table-column>
+        </el-table-column> -->
       </el-table>
     </el-dialog>
 
@@ -557,11 +635,11 @@
               <el-input v-model="touristForm.email" />
             </el-form-item>
           </el-col>
-          <el-col :span="24">
+          <!-- <el-col :span="24">
             <el-form-item label="是否领队">
-              <el-switch v-model="touristForm.isLeader" />
+              <el-switch v-model="touristForm.isLeader" disabled />
             </el-form-item>
-          </el-col>
+          </el-col> -->
           <el-col :span="12">
             <el-form-item label="紧急联系人" prop="emergencyContact">
               <el-input v-model="touristForm.emergencyContact" />
@@ -669,7 +747,8 @@
       </template>
     </el-dialog>
 
-    <el-dialog title="产品详情" width="1000px" v-model="productItemDialogVisible" append-to-body>
+    <el-dialog title="产品详情" width="1000px" v-model="productItemDialogVisible" append-to-body
+      @close="closeProductItemDialog">
       <el-form :model="productForm" :rules="productRules" ref="productFormRef" label-width="120px">
         <div style="margin: 10px 30px;">
           <div style="margin-bottom:8px;">
@@ -692,7 +771,17 @@
             </el-input>
             <el-button size="small" @click="productFormParams.keyword = ''; searchProductList()">清空</el-button>
           </div>
-          <el-table :data="productList" border size="small" max-height="220px" stripe>
+          <div style="margin: 10px" v-if="tempSelectedProducts.length">
+            已选择产品:
+            <el-tag v-for="(item, idx) in tempSelectedProducts" :key="`pt-${idx}`" closable
+              @close="removeProductSelection(item)">{{ item.productName }}</el-tag>
+          </div>
+          <el-table ref="productSelectTableRef" :row-key="(row) => row.id" :data="productList" border size="small"
+            max-height="300px" stripe @selection-change="handlePtSelectionChange" @select="handelPtSelect"
+            @select-all="handlePtSelectAll">
+            <el-table-column type="selection" width="55" />
+            <el-table-column type="index" width="50" />
+
             <el-table-column prop="productName" label="产品名称" min-width="200" />
             <el-table-column prop="productCode" label="产品编码" width="140" />
             <el-table-column prop="type" label="类型" width="120">
@@ -702,55 +791,94 @@
               <template #default="scope">¥{{ (Number(scope.row.price) || Number(scope.row.unitPrice) || 0).toFixed(2)
               }}</template>
             </el-table-column>
-            <el-table-column label="操作" width="120" align="center">
+            <!-- <el-table-column label="操作" width="120" align="center">
               <template #default="scope">
                 <el-button type="primary" size="mini" @click="itemSelectProduct(scope.row.id)">选择</el-button>
               </template>
-            </el-table-column>
+            </el-table-column> -->
           </el-table>
           <el-pagination class="pagination" style="margin: 10px;" background layout="total, prev, pager, next"
-            :page-size="forms.rows" :total="total" @current-change="getProductList">
+            :page-size="forms.rows" :total="productTotal" @current-change="handelProductPageChange">
           </el-pagination>
         </div>
+      </el-form>
 
-        <el-form-item label="选择产品" prop="productID">
-          <span v-if="productForm.productID">{{ productForm.productName }}-{{ productForm.productCode }}</span>
-          <span v-else style="color:#999;">请选择产品</span>
-        </el-form-item>
+      <template #footer>
+        <span class="dialog-footer">
+          <el-button @click="productItemDialogVisible = false">取 消</el-button>
+          <el-button type="primary" @click="submitProductItem">确 定</el-button>
+        </span>
+      </template>
+    </el-dialog>
 
-        <el-form-item label="使用日期" prop="useDate">
-          <el-date-picker v-model="productForm.useDate" disabled type="date" placeholder="选择日期" />
-        </el-form-item>
+    <el-dialog title="上传附件" v-model="attachDialogVisible" width="700px" append-to-body @close="currentOrderId = ''">
+      <div style="margin-bottom:12px;">
+        <el-button type="primary" size="small" @click="downloadTemplate">下载模板</el-button>
+      </div>
+
+      <el-upload ref="orderUploadRef" action="/api/BaseUploader/Basic" :show-file-list="false" :data="uploadParams"
+        :headers="headers" accept=".xls,.xlsx" :limit="10" :on-success="uploadSuccess" :file-list="fileList"
+        :on-error="uploadError" :on-remove="removeFile" :before-upload="beforeUpload" @on-preview="downloadFile">
+        <el-button type="primary" size="small">上传<i class="el-icon-plus"></i></el-button>
+      </el-upload>
+
+      <div class="file-list" style="margin: 10px 0">
+        <el-row v-if="fileList && fileList.length" :gutter="10" style="align-items:center;">
+          <el-col v-for="file in fileList" :key="file.id || file.raw?.uid" :span="24"
+            style="display:flex;align-items:center;justify-content:space-between;margin-bottom:6px;">
+            <div style="flex:1;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;">
+              <a href="javascript:;" @click.prevent="downloadFile(file)" style="color:#409EFF;">
+                {{ file.name }}
+              </a>
+              <span style="color:#999;margin-left:8px;">{{ file.url ? '' : '(本地文件)' }}</span>
+            </div>
+            <div style="margin-left:12px;white-space:nowrap;">
+              <el-button type="text" size="small" @click="downloadFile(file)">下载</el-button>
+              <el-button type="danger" size="small" @click="removeFile(file)">删除</el-button>
+            </div>
+          </el-col>
+        </el-row>
+
+        <div v-else style="text-align:center;color:#999;padding:12px;">暂无附件</div>
+      </div>
 
-        <el-form-item label="数量" prop="quantity">
-          <el-input v-model.number="productForm.quantity" disabled style="width:100px" />
+    </el-dialog>
+
+    <el-dialog :title="`收款`" v-model="paymentDialogVisible" width="500px" append-to-body @close="cancelPayment">
+      <el-form :model="paymentForm" ref="paymentFormRef" label-width="100px">
+        <el-form-item label="收款方式" prop="method">
+          <el-radio-group v-model="paymentForm.method">
+            <el-radio-button label="Online">在线支付</el-radio-button>
+            <el-radio-button label="Balance">余额扣款</el-radio-button>
+            <el-radio-button label="Offline">线下支付</el-radio-button>
+          </el-radio-group>
         </el-form-item>
 
-        <!-- <el-col :span="12">
-            <el-form-item label="单价" prop="price">
-              <el-input-number v-model.number="productForm.price" :min="0" :precision="2" style="width:160px" />
-            </el-form-item>
-          </el-col> -->
+        <el-form-item label="收款金额" prop="amount">
+          <el-input-number v-model.number="paymentForm.amount" disabled :min="0" :precision="2" style="width:200px" />
+        </el-form-item>
 
-        <el-form-item label="描述" prop="remark">
-          <el-input type="textarea" v-model="productForm.remark" :rows="4" />
+        <el-form-item label="订单号" prop="orderNo">
+          <el-input v-model="paymentForm.orderNo" disabled placeholder="可选(线上/线下支付时填写)" />
         </el-form-item>
       </el-form>
 
       <template #footer>
         <span class="dialog-footer">
-          <el-button @click="productItemDialogVisible = false">取 消</el-button>
-          <el-button type="primary" @click="submitProductItem">确 定</el-button>
+          <el-button @click="paymentDialogVisible = false">取 消</el-button>
+          <el-button type="primary" @click="submitPayment">确 定</el-button>
         </span>
       </template>
     </el-dialog>
-  </el-card>
 
+  </el-card>
 </template>
 <script>
 import request from '@/utils/request'
+import store from "@/store";
 import {
   getOrders,
+  getOrderNo,
   delOrder,
   createOrder,
   updateOrder,
@@ -763,23 +891,35 @@ import {
   updateTouristInfo,
   deleteTouristInfo,
 } from '@/api/order';
+import { getPayParams } from '@/api/pay';
+import { delFile, fetchFileList } from '@/api/basic';
 import { getProducts } from '@/api/product';
 import { getProductCategories } from '@/api/productCategory';
-import { cloneDeep } from 'lodash-es';
+import { before, cloneDeep, map, uniqBy } from 'lodash-es';
 import { getTravelAgencies } from '@/api/travelAgency';
 import moment from 'moment/moment';
-import { ProductTypes } from '@/constant';
+import { ProductTypes, FileTypeMap } from '@/constant';
 import utils from '@/utils/util';
 
 export default {
   name: "OrderManage",
   components: {},
   data() {
+    const access_token = sessionStorage.getItem('access_token') || '';
+    const token_type = sessionStorage.getItem('token_type') || '';
+    console.log(this.$store.getters.getUserInfo, '----userInfo---');
     return {
+      headers: {
+        Authorization: token_type + ' ' + access_token,
+      },
+      uploadParams: {},
       ProductTypes,
       productTypeArr: Object.keys(ProductTypes).map((key) => ({ label: ProductTypes[key], value: key })),
       forms: {
         keyword: "",
+        status: "",
+        auditStatus: "",
+        paymentStatus: "",
         columns: [
           { label: "订单号", prop: "orderNo" },
           { label: "旅行社名称", prop: "agencyName" },
@@ -810,10 +950,11 @@ export default {
       formData: {},
       isAdd: true,
       formLabelWidth: "120px",
-      activeTab: ['basic', 'details', 'tourists'],
+      activeTab: ['basic', 'details', 'tourists', 'attachments'],
       currUseDate: '',
       useDateList: [],
       currentOrderId: '',
+      currentOrderNo: '',
       categoryOptions: [],
       agencyOptions: [],
       formRules: {
@@ -899,6 +1040,7 @@ export default {
       },
       productDialogVisible: false,
       productItemDialogVisible: false,
+      tempSelectedProducts: [],
       productForm: {},
       productFormParams: {
         keyword: "",
@@ -931,6 +1073,14 @@ export default {
           { max: 500, message: '长度不能超过500个字符', trigger: 'blur' }
         ]
       },
+      attachDialogVisible: false,
+      fileList: [],
+      paymentDialogVisible: false,
+      paymentForm: {
+        amount: null,
+        method: 'Online',
+        orderNo: '',
+      },
     };
   },
   methods: {
@@ -954,7 +1104,14 @@ export default {
       this.productFormParams.page = 1;
       this.getProductList();
     },
-    getProductList() {
+    async handelProductPageChange(page) {
+      this.productFormParams.page = page;
+      await this.getProductList();
+      this.$nextTick(() => {
+        this.updatePtCheckStatus();
+      });
+    },
+    async getProductList() {
       this.productFormParams.filters = [];
       if (this.productType) {
         this.productFormParams.filters = [
@@ -965,10 +1122,9 @@ export default {
           }
         ]
       }
-      getProducts(this.productFormParams).then((res) => {
-        this.productList = res.data?.data || [];
-        this.productTotal = res.data?.records || 0;
-      });
+      const res = await getProducts(this.productFormParams)
+      this.productList = res.data?.data || [];
+      this.productTotal = res.data?.records || 0;
     },
     getTravelAgencies() {
       getTravelAgencies({
@@ -986,6 +1142,10 @@ export default {
         this.agencyOptions = res.data?.data || [];
       });
     },
+    searchOrderList() {
+      this.forms.page = 1;
+      this.getOrderList();
+    },
     sizeHandler(val) {
       this.forms.rows = val;
       this.getOrderList();
@@ -998,21 +1158,61 @@ export default {
       this.isAdd = false;
       this.searchProductList();
       this.getTravelAgencies();
+      this.currentOrderId = row.id;
       const res = await getOrderDetailById(row.id);
       this.formData = cloneDeep(res.data);
       this.formDialogVisible = true;
     },
-    add(row) {
+    async add(row) {
+      const res = await getOrderNo();
+      if (res?.code === 200) {
+        this.currentOrderNo = res.data;
+      } else {
+        this.$message.error(res.data?.message);
+        return;
+      }
+      this.fileList = [];
       this.isAdd = true;
       this.searchProductList();
       this.getTravelAgencies();
       this.formDialogVisible = true;
-      this.formData = {};
+      this.formData = {
+        agencyID: this.userAgencyId,
+        tourists: [],
+        details: [],
+      };
     },
     close() {
+      this.currentOrderId = '';
+      this.currentOrderNo = '';
       this.$refs.formRef.resetFields();
     },
     getOrderList() {
+      this.forms.filters = [];
+      if (this.forms.status) {
+        this.forms.filters = [
+          {
+            name: 'status',
+            operate: 0,
+            value: this.forms.status
+          }
+        ]
+      }
+      if (this.forms.auditStatus) {
+        this.forms.filters.push({
+          name: 'auditStatus',
+          operate: 0,
+          value: this.forms.auditStatus
+        })
+      }
+      if (this.forms.paymentStatus) {
+        this.forms.filters.push({
+          name: 'paymentStatus',
+          operate: 0,
+          value: this.forms.paymentStatus
+        })
+      }
+
       getOrders(this.forms || {}).then((res) => {
         this.tableData = res.data?.data || []
         this.total = res.data?.records || 0
@@ -1025,12 +1225,16 @@ export default {
           this.$message.error('请至少添加一个产品');
           return;
         }
-        if (!this.formData.tourists?.length) {
-          this.$message.error('请至少添加一个游客');
+        const hasLeader = this.formData.tourists?.some(item => item.isLeader);
+        if (!hasLeader) {
+          this.$message.error('请至少添加一个领队');
           return;
         }
         this.formData.touristCount = this.formData.tourists.length;
         const opt = this.isAdd ? createOrder : updateOrder;
+        if (this.currentOrderNo) {
+          this.formData.orderNo = this.currentOrderNo;
+        }
         opt(this.formData).then((res) => {
           if (res.code === 200) {
             this.$message({
@@ -1050,7 +1254,20 @@ export default {
         that.$refs.table.toggleRowExpansion(row);
       });
     },
-
+    async payment(row) {
+      const res = await getPayParams(row.id);
+      console.log('---pay params---', res);
+      this.paymentForm.orderNo = row.orderNo;
+      this.paymentForm.amount = row.totalAmount;
+      this.paymentDialogVisible = true;
+    },
+    cancelPayment() {
+      this.paymentForm = {
+        amount: null,
+        method: 'Online',
+        orderNo: '',
+      };
+    },
     del(row) {
       this.$confirm("此操作将删除选择数据, 是否继续?", "提示", { confirmButtonText: "确定", cancelButtonText: "取消", type: "warning", })
         .then(() => {
@@ -1104,6 +1321,9 @@ export default {
       this.formData.details.splice(index, 1);
       this.formData.totalAmount = (this.formData.details || []).reduce((s, p) => s + (Number(p.unitPrice) || 0) * (Number(p.quantity) || 0), 0)
     },
+    removeProductSelection(item) {
+      this.$refs.productSelectTableRef?.toggleRowSelection(item, false);
+    },
     itemSelectProduct(value, row) {
       const product = this.productList.find(item => item.id === value);
       if (!product) return;
@@ -1121,20 +1341,73 @@ export default {
         this.productForm.productType = ProductTypes[product.type] || product.type;
       }
     },
+    closeProductItemDialog() {
+      this.$refs.productSelectTableRef?.clearSelection();
+      this.tempSelectedProducts = [];
+    },
+    handlePtSelectionChange(rows) {
+    },
+    setPtSelection() { },
+    handelPtSelect(selectedRows, row) {
+      this.productList.forEach((product) => {
+        if (selectedRows.find((sr) => sr.id === product.id)) {
+          this.tempSelectedProducts.push(({ id: product.id, productName: product.productName }))
+        } else {
+          this.tempSelectedProducts = this.tempSelectedProducts.filter((item) => item.id !== product.id);
+        }
+      })
+      this.tempSelectedProducts = uniqBy(this.tempSelectedProducts, 'id');
+    },
+    handlePtSelectAll(selectedRows) {
+      this.productList.forEach((product) => {
+        if (selectedRows.find((sr) => sr.id === product.id)) {
+          this.tempSelectedProducts.push(({ id: product.id, productName: product.productName }))
+        } else {
+          this.tempSelectedProducts = this.tempSelectedProducts.filter((item) => item.id !== product.id);
+        }
+      })
+      this.tempSelectedProducts = uniqBy(this.tempSelectedProducts, 'id');
+    },
+    updatePtCheckStatus() {
+      debugger;
+      this.$refs.productSelectTableRef?.clearSelection();
+      this.productList.forEach((product) => {
+        this.$refs.productSelectTableRef?.toggleRowSelection(product, !!this.tempSelectedProducts.find((item) => item.id === product.id));
+      });
+    },
     submitProductItem() {
-      this.$refs.productFormRef.validate(valid => {
-        if (valid) {
-          this.productItemDialogVisible = false;
-          this.formData.totalAmount = (this.formData.details || []).reduce((s, p) => s + (Number(p.unitPrice) || 0) * (Number(p.quantity) || 0), 0)
-          if (!this.formData.details.find((d) => d.uid === this.productForm.uid)) {
-            this.formData.details.push(this.productForm)
-          }
-          this.productForm = {};
+      if (!this.tempSelectedProducts.length) {
+        this.$message.error('请选择产品');
+        return;
+      }
+
+      this.tempSelectedProducts.forEach((item) => {
+        if (!this.formData.details.find((d) => d.productID === item.id)) {
+          this.formData.details.push({
+            productID: item.id,
+            productName: item.productName,
+            productCode: item.productCode,
+            productType: ProductTypes[item.type] || item.type,
+            unitPrice: item.price,
+            useDate: this.currUseDate,
+            quantity: 1,
+            remark: ''
+          });
         }
       });
+
+      this.productItemDialogVisible = false;
+      this.formData.totalAmount = (this.formData.details || []).reduce((s, p) => s + (Number(p.unitPrice) || 0) * (Number(p.quantity) || 0), 0)
     },
-    addTouristInfo() {
+    addTouristItem(isLeader = false) {
       this.formData.tourists = this.formData.tourists || []
+      if (isLeader) {
+        const hasLeader = this.formData.tourists.find(t => t.isLeader);
+        if (hasLeader) {
+          this.$message.error('已存在领队游客,不能重复添加');
+          return;
+        }
+      }
       this.touristForm = {
         uid: `tourist-item-${utils.getUUID(8, 16)}`,
         touristName: '',
@@ -1143,7 +1416,7 @@ export default {
         idNumber: '',
         phone: '',
         passengerType: 'Adult',
-        isLeader: !this.formData.tourists.length,
+        isLeader: !!isLeader,
         emergencyContact: '',
         emergencyPhone: '',
         specialRequirements: '',
@@ -1301,7 +1574,74 @@ export default {
         'Student': '学生'
       };
       return types[type] || type;
-    }
+    },
+    async attachment(row) {
+      this.currentOrderNo = row.orderNo;
+      const res = await fetchFileList('', this.currentOrderNo)
+
+      this.fileList = (res?.data || []).map(file => ({
+        id: file.id,
+        name: file.name,
+        url: file.url,
+        status: 'success',
+        raw: {
+          uid: `upload-file-${file.id}`,
+        }
+      }));
+      this.attachDialogVisible = true;
+    },
+    downloadTemplate() {
+      const link = document.createElement('a');
+      link.href = '/证件号导入模板.xlsx';
+      link.download = '证件号导入模板.xlsx';
+      document.body.appendChild(link);
+      link.click();
+      document.body.removeChild(link);
+    },
+    uploadSuccess(res, file, fileList) {
+      console.log(res, file, fileList, 'uploadSuccess');
+      if (res.code === 200) {
+        const fileInfo = res.data[0];
+        file.id = fileInfo.id;
+        file.url = fileInfo.path;
+        this.$message.success(file.name + ' 上传成功');
+      } else {
+        this.$message.error(file.name + ' 上传失败: ' + res.content);
+        this.fileList = this.fileList.filter(f => f.raw.uid !== file.raw.uid);
+      }
+    },
+    uploadError(err, file) {
+      console.log(err, file);
+      this.$message.error(file.name + ' 上传失败');
+      this.fileList = this.fileList.filter(f => f.raw.uid !== file.raw.uid);
+    },
+    beforeUpload(file) {
+      this.uploadParams = {
+        fileCode: this.currentOrderNo,
+        // fileCode: utils.getUUID(8, 16),
+        fileType: FileTypeMap[file.type] || 'Other',
+        // folderID: 'OrderAttachments',
+        dataType: 'OrderTourist'
+      };
+      const isLt10M = file.size / 1024 / 1024 < 10;
+      if (!isLt10M) { $message.error('单个文件不能超过 10MB'); }
+      return isLt10M;
+    },
+    downloadFile(file) {
+      console.log(file, 'downloadFile');
+      window.open(file.url);
+    },
+    removeFile(file, fileList) {
+      this.$confirm('确认删除该附件?')
+        .then(() => {
+          if (file.id) {
+            delFile(file.id).then(() => {
+              this.$message.success('删除成功');
+            });
+          }
+          this.fileList = this.fileList.filter(f => f.raw.uid !== file.raw.uid);
+        });
+    },
   },
   computed: {
     travelInfo() {
@@ -1309,6 +1649,15 @@ export default {
         travelStartDate: this.formData.travelStartDate,
         travelDays: this.formData.travelDays,
       };
+    },
+    userInfo() {
+      return store.getters.getUserInfo;
+    },
+    userAccountId() {
+      return store.getters.getUserInfo?.account || '';
+    },
+    userAgencyId() {
+      return store.getters.getUserInfo?.agencys[0] || '';
     }
   },
   watch: {
@@ -1343,4 +1692,12 @@ export default {
     this.getTravelAgencies();
   },
 };
-</script>
+</script>
+
+<style lang="less" scoped>
+.search-form {
+  .el-form-item {
+    margin-bottom: 0;
+  }
+}
+</style>

+ 3 - 3
src/views/order/review.vue

@@ -154,9 +154,9 @@ export default {
         ],
         filters: [
           {
-            name: "auditStatus",
-            operate: 1,
-            value: 'Approved',
+            name: "status",
+            operate: 1, // 0 等于; 1 不等于; 2 like; 3 not like
+            value: 'Paid',
           }
         ],
         page: 1,

+ 131 - 0
src/views/payment/index.vue

@@ -0,0 +1,131 @@
+<template>
+  <div class="payment-container">
+    <div class="payment-header">
+      <button @click="goBack" class="back-btn">←</button>
+      <h1>支付</h1>
+    </div>
+
+    <div class="payment-content">
+      <div class="order-info">
+        <p>订单号: {{ orderNo }}</p>
+        <p class="amount">¥{{ amount }}</p>
+      </div>
+
+      <div class="payment-method">
+        <p class="method-title">支付方式</p>
+        <div class="method-item">
+          <span class="icon">💬</span>
+          <span class="name">微信支付</span>
+        </div>
+      </div>
+
+      <button @click="confirmPayment" :disabled="loading" class="confirm-btn">
+        {{ loading ? '处理中...' : '确认支付' }}
+      </button>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'Payment',
+  data() {
+    return {
+      orderNo: '20240115001',
+      amount: '199.99',
+      selectedMethod: 'wechat',
+      loading: false,
+      methods: [
+        { id: 'wechat', name: '微信支付', icon: '💬' },
+        { id: 'alipay', name: '支付宝', icon: '🔵' },
+        { id: 'card', name: '银行卡', icon: '💳' }
+      ]
+    };
+  },
+  methods: {
+    goBack() {
+      this.$router.go(-1);
+    },
+    confirmPayment() {
+      this.loading = true;
+      setTimeout(() => {
+        this.$router.push('/order/success');
+        this.loading = false;
+      }, 2000);
+    }
+  }
+};
+</script>
+
+<style scoped>
+.payment-container {
+  padding: 20px;
+}
+
+.payment-header {
+  display: flex;
+  align-items: center;
+  margin-bottom: 30px;
+}
+
+.back-btn {
+  background: none;
+  border: none;
+  font-size: 24px;
+  cursor: pointer;
+  margin-right: 10px;
+}
+
+.order-info {
+  background: #f5f5f5;
+  padding: 20px;
+  border-radius: 8px;
+  margin-bottom: 30px;
+}
+
+.amount {
+  font-size: 24px;
+  font-weight: bold;
+  color: #e74c3c;
+}
+
+.method-title {
+  margin-bottom: 15px;
+  font-weight: bold;
+}
+
+.method-item {
+  display: flex;
+  align-items: center;
+  padding: 15px;
+  background: #f9f9f9;
+  border-radius: 8px;
+  margin-bottom: 30px;
+}
+
+.icon {
+  font-size: 24px;
+  margin-right: 10px;
+}
+
+.confirm-btn {
+  width: 100%;
+  padding: 12px;
+  background: #09bb07;
+  color: white;
+  border: none;
+  border-radius: 8px;
+  font-size: 16px;
+  cursor: pointer;
+  transition: background 0.3s;
+}
+
+.confirm-btn:disabled {
+  background: #ccc;
+  cursor: not-allowed;
+}
+
+.confirm-btn:hover:not(:disabled) {
+  background: #08a806;
+}
+</style>

+ 213 - 0
src/views/payment/success.vue

@@ -0,0 +1,213 @@
+<template>
+  <div class="success-page">
+    <div class="card">
+      <div class="icon-wrap">
+        <svg class="icon-check" viewBox="0 0 24 24" aria-hidden="true">
+          <circle cx="12" cy="12" r="10" fill="#e6f9ef"></circle>
+          <path d="M7.5 12.5l2.5 2.5 6-6" fill="none" stroke="#06b981" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/>
+        </svg>
+      </div>
+
+      <h1 class="title">支付成功</h1>
+      <p class="subtitle">感谢您的订单,支付已完成</p>
+
+      <div class="info">
+        <div class="row">
+          <span class="label">订单号</span>
+          <span class="value order" @click="copyOrder">{{ orderId || '—' }}</span>
+        </div>
+        <div class="row">
+          <span class="label">支付方式</span>
+          <span class="value">{{ paymentMethod || '—' }}</span>
+        </div>
+        <div class="row">
+          <span class="label">支付金额</span>
+          <span class="value amount">{{ formattedAmount }}</span>
+        </div>
+        <div class="row">
+          <span class="label">支付时间</span>
+          <span class="value">{{ paidAt }}</span>
+        </div>
+      </div>
+
+      <!-- 跳转功能已移除,只保留信息展示 -->
+    </div>
+  </div>
+</template>
+
+<script setup>
+import { ref, computed } from 'vue'
+import { useRoute } from 'vue-router'
+
+const route = useRoute()
+
+// 从路由 query 或 params 获取信息(兼容常见场景)
+const orderId = route.query.orderId || route.params.orderId || route.query.order || ''
+const amountRaw = route.query.amount || route.query.total || route.params.amount || ''
+const paymentMethod = route.query.method || route.query.payMethod || route.params.method || '未知'
+const paidAt = route.query.time || new Date().toLocaleString()
+
+const amount = computed(() => {
+  const n = parseFloat(amountRaw)
+  return Number.isFinite(n) ? n : null
+})
+const formattedAmount = computed(() => {
+  if (amount.value == null) return '—'
+  // 简单货币格式化(人民币)
+  return '¥' + amount.value.toFixed(2)
+})
+
+// 简单复制订单号
+const copyOrder = async () => {
+  if (!orderId) return
+  try {
+    await navigator.clipboard.writeText(String(orderId))
+    toast('订单号已复制')
+  } catch {
+    // 退回到选择文本方式(兼容性)
+    const el = document.createElement('textarea')
+    el.value = String(orderId)
+    document.body.appendChild(el)
+    el.select()
+    document.execCommand('copy')
+    document.body.removeChild(el)
+    toast('订单号已复制')
+  }
+}
+
+// 简易 toast(非常轻量)
+const toastTimer = ref(null)
+const toastText = ref('')
+function toast(text = '', ms = 1500) {
+  clearTimeout(toastTimer.value)
+  toastText.value = text
+  const box = document.createElement('div')
+  box.textContent = text
+  box.style.position = 'fixed'
+  box.style.left = '50%'
+  box.style.bottom = '18%'
+  box.style.transform = 'translateX(-50%)'
+  box.style.background = 'rgba(0,0,0,0.7)'
+  box.style.color = '#fff'
+  box.style.padding = '8px 12px'
+  box.style.borderRadius = '6px'
+  box.style.fontSize = '14px'
+  box.style.zIndex = '9999'
+  document.body.appendChild(box)
+  setTimeout(() => document.body.removeChild(box), ms)
+}
+</script>
+
+<style scoped>
+.success-page {
+  min-height: 100vh;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  background: #fafafa;
+  padding: 20px;
+  box-sizing: border-box;
+}
+
+.card {
+  width: 100%;
+  max-width: 420px;
+  background: #fff;
+  border-radius: 12px;
+  padding: 28px 20px;
+  box-shadow: 0 6px 24px rgba(24, 39, 75, 0.06);
+  text-align: center;
+}
+
+.icon-wrap {
+  display: flex;
+  justify-content: center;
+  margin-bottom: 8px;
+}
+
+.icon-check {
+  width: 72px;
+  height: 72px;
+}
+
+.title {
+  margin: 6px 0 4px;
+  font-size: 20px;
+  color: #111827;
+}
+
+.subtitle {
+  margin: 0 0 18px;
+  color: #6b7280;
+  font-size: 13px;
+}
+
+.info {
+  border-top: 1px solid #f3f4f6;
+  border-bottom: 1px solid #f3f4f6;
+  padding: 12px 0;
+  margin-bottom: 18px;
+}
+
+.row {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 8px 0;
+  font-size: 14px;
+  color: #374151;
+}
+
+.label {
+  color: #6b7280;
+}
+
+.value {
+  font-weight: 600;
+}
+
+.value.order {
+  color: #2563eb;
+  text-decoration: underline;
+  cursor: pointer;
+  font-weight: 500;
+}
+
+.amount {
+  color: #10b981;
+}
+
+.actions {
+  display: flex;
+  gap: 10px;
+  margin-bottom: 12px;
+}
+
+.btn {
+  flex: 1;
+  padding: 10px 12px;
+  border-radius: 8px;
+  border: 1px solid #e5e7eb;
+  background: #fff;
+  color: #111827;
+  font-size: 15px;
+}
+
+.btn.primary {
+  background: linear-gradient(90deg,#10b981,#06b6d4);
+  color: #fff;
+  border: none;
+}
+
+.tip {
+  font-size: 12px;
+  color: #9ca3af;
+}
+
+/* small devices */
+@media (max-width: 360px) {
+  .card { padding: 18px 14px; }
+  .icon-check { width: 60px; height: 60px; }
+  .title { font-size: 18px; }
+}
+</style>

+ 22 - 7
src/views/product/index.vue

@@ -69,6 +69,11 @@
           </el-tag>
         </template>
       </el-table-column>
+      <el-table-column label="是否启用" width="140">
+        <template #default="scope">
+          <span>{{ scope.row.isEnabled ? '启用' : '禁用' }}</span>
+        </template>
+      </el-table-column>
       <!-- <el-table-column label="推荐/热门" width="120">
         <template #default="scope">
           <el-tag v-if="scope.row.isRecommend" type="success" effect="plain" size="small">推荐</el-tag>
@@ -134,6 +139,11 @@
                   </el-select>
                 </el-form-item>
               </el-col>
+              <el-col :span="12">
+                <el-form-item label="是否启用" prop="price">
+                  <el-switch v-model="formData.isEnabled" active-text="启用" inactive-text="禁用"></el-switch>
+                </el-form-item>
+              </el-col>
               <el-col :span="24">
                 <el-form-item label="主图" prop="mainImageUrl">
                   <el-upload class="avatar-uploader" :action="uploadUrl" :show-file-list="false"
@@ -259,13 +269,12 @@
                   </el-radio-group>
                 </el-form-item>
               </el-col>
-              <el-col :span="24">
+              <!-- <el-col :span="24">
                 <el-form-item label="标记">
-                  <el-switch v-model="formData.isEnabled" active-text="启用"></el-switch>
-                  <el-switch v-model="formData.isRecommend" active-text="推荐"></el-switch>
-                  <el-switch v-model="formData.isHot" active-text="热门"></el-switch>
+                  <el-switch v-model="formData.isRecommend" active-text="推荐" inactive-text=""></el-switch>
+                  <el-switch v-model="formData.isHot" active-text="热门" inactive-text=""></el-switch>
                 </el-form-item>
-              </el-col>
+              </el-col> -->
             </el-row>
           </el-tab-pane>
         </el-tabs>
@@ -301,6 +310,7 @@ export default {
           { label: "类型", prop: "type" },
           { label: "价格", prop: "price" },
           { label: "状态", prop: "status" },
+          { label: "是否启用", prop: "isEnabled" },
         ],
         sorters: [
           {
@@ -384,6 +394,7 @@ export default {
       this.isAdd = false;
       this.getProductCategories();
       const res = await getProductById(row.id);
+      console.log(res, '1213');
       this.formData = cloneDeep(res.data);
       this.formDialogVisible = true;
     },
@@ -391,7 +402,10 @@ export default {
       this.activeTab = 'basic';
       this.isAdd = true;
       this.formDialogVisible = true;
-      this.formData = {};
+      this.formData = {
+        isEnabled: true,
+        status: 'OnSale',
+      };
       this.getProductCategories();
     },
     close() {
@@ -399,6 +413,7 @@ export default {
     },
     getProductList() {
       getProducts(this.forms || {}).then((res) => {
+        console.log(res);
         this.tableData = res.data?.data || []
         this.total = res.data?.records || 0
       });
@@ -407,7 +422,7 @@ export default {
     submit() {
       this.$refs.formRef.validate((valid) => {
         if (!valid) return;
-
+        console.log(this.formData, 'formdata');
         submitProduct(this.formData).then((res) => {
           if (res.code === 200) {
             this.$message({

+ 57 - 57
src/views/sys/menu/index.vue

@@ -15,8 +15,8 @@
         </el-form-item> -->
         <el-form-item label="类别" prop="category">
           <el-col>
-            <el-select v-model="category" placeholder="请选择类别" required @change="getMenus();" style="min-width: 120px;" >
-              <el-option v-for="value in categorys" :label="value" :value="value"></el-option>
+            <el-select v-model="category" placeholder="请选择类别" required @change="getMenus();" style="min-width: 120px;">
+              <el-option v-for="value in categorys" :key="value" :label="value" :value="value"></el-option>
             </el-select>
           </el-col>
         </el-form-item>
@@ -69,75 +69,75 @@
         </template>
       </el-table-column>
     </el-table>
-  </el-card>
-
-  <el-dialog title="菜单维护" width="600px" destroy-on-close v-model="formDialogVisible" @close="close">
-    <el-form :model="forms" :rules="rules" ref="forms" :label-width="formLabelWidth">
-      <el-row :gutter="10">
-        <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
-          <el-form-item label="菜单类别" prop="category">
-            <el-select v-model="forms.category" placeholder="请选择类别" required>
-              <el-option v-for="value in categorys" :label="value" :value="value"></el-option>
-            </el-select>
-          </el-form-item>
-        </el-col>
-        <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
-          <el-form-item label="上级菜单">
-            <!-- <el-select v-model="forms.parentID" placeholder="请选择上级菜单" disabled>
+    <el-dialog title="菜单维护" width="600px" destroy-on-close v-model="formDialogVisible" @close="close">
+      <el-form :model="forms" :rules="rules" ref="forms" :label-width="formLabelWidth">
+        <el-row :gutter="10">
+          <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+            <el-form-item label="菜单类别" prop="category">
+              <el-select v-model="forms.category" placeholder="请选择类别" required>
+                <el-option v-for="value in categorys" :key="value" :label="value" :value="value"></el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+            <el-form-item label="上级菜单">
+              <!-- <el-select v-model="forms.parentID" placeholder="请选择上级菜单" disabled>
               <el-option label="根菜单" value=""></el-option>
             </el-select> -->
-            <el-tree-select v-model="forms.parentID" :data="menuSelect" check-strictly :render-after-expand="false" />
-          </el-form-item>
-        </el-col>
-        <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
-          <el-form-item label="菜单名称" prop="name">
-            <el-input v-model="forms.name" autocomplete="off"></el-input>
-          </el-form-item>
-        </el-col>
-        <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
-          <el-form-item label="菜单编号">
-            <el-input v-model="forms.code" autocomplete="off"></el-input>
-          </el-form-item>
-        </el-col>
-        <!-- <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+              <el-tree-select v-model="forms.parentID" :data="menuSelect" check-strictly :render-after-expand="false" />
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+            <el-form-item label="菜单名称" prop="name">
+              <el-input v-model="forms.name" autocomplete="off"></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+            <el-form-item label="菜单编号">
+              <el-input v-model="forms.code" autocomplete="off"></el-input>
+            </el-form-item>
+          </el-col>
+          <!-- <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
           <el-form-item label="菜单类型">
             <el-radio v-model="forms.menuType" label="page">菜单</el-radio>
             <el-radio v-model="forms.menuType" label="button">按钮</el-radio>
           </el-form-item>
         </el-col> -->
-        <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
-          <el-form-item label="排序号">
-            <el-input-number v-model="forms.sortCode" :min="1" :max="9999999" label="排序号"></el-input-number>
-          </el-form-item>
-        </el-col>
-        <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
-          <el-form-item label="样式图标">
-            <el-input v-model="forms.icon" autocomplete="off"></el-input>
-          </el-form-item>
-        </el-col>
-        <!-- <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+          <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+            <el-form-item label="排序号">
+              <el-input-number v-model="forms.sortCode" :min="1" :max="9999999" label="排序号"></el-input-number>
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+            <el-form-item label="样式图标">
+              <el-input v-model="forms.icon" autocomplete="off"></el-input>
+            </el-form-item>
+          </el-col>
+          <!-- <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
           <el-form-item label="菜单状态">
             <el-radio v-model="forms.status" label="enabled">启用</el-radio>
             <el-radio v-model="forms.status" label="disabled">禁用</el-radio>
           </el-form-item>
         </el-col> -->
-        <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
-          <el-form-item label="路由地址">
-            <el-input v-model="forms.target" autocomplete="off"></el-input>
-          </el-form-item>
-        </el-col>
-      </el-row>
-    </el-form>
-    <template #footer>
-      <span class="dialog-footer">
-        <el-button @click="formDialogVisible = false">取 消</el-button>
-        <el-button type="primary" @click="submit()">确 定</el-button>
-      </span>
-    </template>
-  </el-dialog>
+          <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+            <el-form-item label="路由地址">
+              <el-input v-model="forms.target" autocomplete="off"></el-input>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      <template #footer>
+        <span class="dialog-footer">
+          <el-button @click="formDialogVisible = false">取 消</el-button>
+          <el-button type="primary" @click="submit()">确 定</el-button>
+        </span>
+      </template>
+    </el-dialog>
+  </el-card>
+
 </template>
 <script>
-import { fetchMenus,fetchMenuDetail, submitMenu, delMenu } from "@/api/basic";
+import { fetchMenus, fetchMenuDetail, submitMenu, delMenu } from "@/api/basic";
 export default {
   name: "MenuPage",
   components: {},

+ 54 - 56
src/views/sys/role/index.vue

@@ -49,67 +49,66 @@
         <span style="margin-left: 10px">{{ (scope.row.birthday || "").split(" ")[0] }}</span>
       </template>
     </static-table>
-  </el-card>
-
-  <static-dialog ref="dialog" class="dialog" title="角色维护" :opened="opened" :ok="submit">
-    <el-form :model="forms" :rules="formRules" ref="forms" :label-width="formLabelWidth">
-      <el-row :gutter="10">
-        <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
-          <el-form-item label="角色类别" prop="category">
-            <el-select v-model="forms.category" placeholder="请选择类别" required>
-              <el-option label="通用" value="global"></el-option>
-              <el-option label="权限" value="permission"></el-option>
-            </el-select>
-          </el-form-item>
-        </el-col>
-        <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
-          <el-form-item label="角色名称" prop="name">
-            <el-input v-model="forms.name" autocomplete="off"></el-input>
-          </el-form-item>
-        </el-col>
-        <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
-          <el-form-item label="角色编码" prop="code">
-            <el-input v-model="forms.code" autocomplete="off"></el-input>
-          </el-form-item>
-        </el-col>
-        <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
-          <el-form-item label="排序号" prop="sortCode">
-            <el-input-number v-model="forms.sortCode" :min="1" :max="9999999" label="排序号"></el-input-number>
-          </el-form-item>
-        </el-col>
-        <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
-          <el-form-item label="备注">
-            <el-input type="textarea" placeholder="请输入备注内容" v-model="forms.remark" autocomplete="off" show-word-limit
-              :rows="2"></el-input>
-          </el-form-item>
-        </el-col>
-      </el-row>
-    </el-form>
-  </static-dialog>
+    <static-dialog ref="dialog" class="dialog" title="角色维护" :opened="opened" :ok="submit">
+      <el-form :model="forms" :rules="formRules" ref="forms" :label-width="formLabelWidth">
+        <el-row :gutter="10">
+          <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+            <el-form-item label="角色类别" prop="category">
+              <el-select v-model="forms.category" placeholder="请选择类别" required>
+                <el-option label="通用" value="global"></el-option>
+                <el-option label="权限" value="permission"></el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+            <el-form-item label="角色名称" prop="name">
+              <el-input v-model="forms.name" autocomplete="off"></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+            <el-form-item label="角色编码" prop="code">
+              <el-input v-model="forms.code" autocomplete="off"></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+            <el-form-item label="排序号" prop="sortCode">
+              <el-input-number v-model="forms.sortCode" :min="1" :max="9999999" label="排序号"></el-input-number>
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+            <el-form-item label="备注">
+              <el-input type="textarea" placeholder="请输入备注内容" v-model="forms.remark" autocomplete="off" show-word-limit
+                :rows="2"></el-input>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+    </static-dialog>
 
-  <static-dialog ref="userDialog" class="dialog" title="角色用户" :ok="userSubmit" width="960">
-    <user-select ref="userSelect"></user-select>
-  </static-dialog>
+    <static-dialog ref="userDialog" class="dialog" title="角色用户" :ok="userSubmit" width="960">
+      <user-select ref="userSelect"></user-select>
+    </static-dialog>
 
-  <static-dialog ref="powerDialog" class="dialog" title="权限维护" :ok="powerSubmit">
-    <!-- <el-select v-model="menuCategory" placeholder="请选择类别" required @change="fetctMenuData();">
+    <static-dialog ref="powerDialog" class="dialog" title="权限维护" :ok="powerSubmit">
+      <!-- <el-select v-model="menuCategory" placeholder="请选择类别" required @change="fetctMenuData();">
       <el-option v-for="value in menuCategorys" :label="value" :value="value"></el-option>
     </el-select> -->
-    <el-scrollbar style="height: 45vh; width:30%;">
-      <el-tree ref="powerTree" :data="treeData" show-checkbox node-key="id" default-expand-all
-        @check-change="checkEvent" :props="defaultProps">
-        <template #default="{ node, data }">
-          <span class="custom-tree-node">
-            <span>
-              <component :is="data.icon" style="width: 15px; height:15px;" />
-              {{ node.label }}
+      <el-scrollbar style="height: 45vh; width:30%;">
+        <el-tree ref="powerTree" :data="treeData" show-checkbox node-key="id" default-expand-all
+          @check-change="checkEvent" :props="defaultProps">
+          <template #default="{ node, data }">
+            <span class="custom-tree-node">
+              <span>
+                <component :is="data.icon" style="width: 15px; height:15px;" />
+                {{ node.label }}
+              </span>
             </span>
-          </span>
-        </template>
-      </el-tree>
-    </el-scrollbar>
+          </template>
+        </el-tree>
+      </el-scrollbar>
+    </static-dialog>
+  </el-card>
 
-  </static-dialog>
 </template>
 <script>
 import { fetchMenus } from "@/api/basic";
@@ -125,7 +124,6 @@ export default {
     return {
       // menuCategory: '后台',
       // menuCategorys: ['后台', '侧边栏'],
-
       currRow: null,
       querys: {
         keyword: "",

+ 181 - 104
src/views/sys/user/index.vue

@@ -44,7 +44,6 @@
       <el-button type="primary" icon="plus" @click="add()">新增</el-button>
       <el-button type="danger" icon="delete" @click="del()">删除</el-button>
       <el-button type="success" icon="Refresh" @click="reset()">重置密码</el-button>
-
       <el-button plain icon="Download" @click="fetchs('Export')">导出</el-button>
     </div>
 
@@ -53,6 +52,7 @@
       <template v-slot:toolbar="scope">
         <el-button @click="edit(scope.row)" link size="small" type="primary">[编辑]</el-button>
         <el-button @click="openRole(scope.row)" link size="small" type="primary">[角色]</el-button>
+        <el-button @click="openRelation(scope.row)" link size="small" type="primary">[关联旅行社]</el-button>
       </template>
       <template v-slot:isEnabled="scope">
         <el-switch v-model="scope.row.isEnabled" active-color="#13ce66" inactive-color="#ff4949" active-text=""
@@ -66,108 +66,136 @@
         <span style="margin-left: 10px">{{ (scope.row.birthday || "").split(" ")[0] }}</span>
       </template>
     </static-table>
-  </el-card>
-
-  <static-dialog ref="dialog" class="dialog" title="用户维护" :opened="opened" :ok="submit">
-    <el-form :model="forms" :rules="rules" ref="forms" :label-width="labelWidth">
-      <el-row :gutter="10">
-        <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
-          <el-form-item label="所属公司" prop="companyID">
-            <el-tree-select v-model="forms.companyID" :data="companys"
-              @change="forms.departmentID = ''; companyChange(forms.companyID)" check-strictly
-              :render-after-expand="false" />
-          </el-form-item>
-        </el-col>
-        <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
-          <el-form-item label="所属部门" prop="departmentID">
-            <!-- <el-select v-model="forms.parentID" placeholder="请选择上级菜单" disabled>
+    <static-dialog ref="dialog" class="dialog" title="用户维护" :opened="opened" :ok="submit">
+      <el-form :model="forms" :rules="rules" ref="forms" :label-width="labelWidth">
+        <el-row :gutter="10">
+          <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+            <el-form-item label="所属公司" prop="companyID">
+              <el-tree-select v-model="forms.companyID" :data="companys"
+                @change="forms.departmentID = ''; companyChange(forms.companyID)" check-strictly
+                :render-after-expand="false" />
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+            <el-form-item label="所属部门" prop="departmentID">
+              <!-- <el-select v-model="forms.parentID" placeholder="请选择上级菜单" disabled>
               <el-option label="根菜单" value=""></el-option>
             </el-select> -->
-            <el-tree-select v-model="forms.departmentID" :data="departments" check-strictly
-              :render-after-expand="false" />
-          </el-form-item>
-        </el-col>
-
-        <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
-          <el-form-item label="用户账户" prop="account">
-            <el-input v-model="forms.account" autocomplete="off"></el-input>
-          </el-form-item>
-        </el-col>
-        <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
-          <el-form-item label="姓名" prop="realName">
-            <el-input v-model="forms.realName" autocomplete="off"></el-input>
-          </el-form-item>
-        </el-col>
-        <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
-          <el-form-item label="手机号" prop="mobile">
-            <el-input v-model="forms.mobile" autocomplete="off"></el-input>
-          </el-form-item>
-        </el-col>
-        <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
-          <el-form-item label="生日">
-            <el-date-picker v-model="forms.birthday" type="date" placeholder="选择生日" format="YYYY-MM-DD"
-              :editable="false">
-            </el-date-picker>
-          </el-form-item>
-        </el-col>
-
-        <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" v-if="!forms.id">
-          <el-form-item label="密码" prop="password">
-            <el-input v-model="forms.password" placeholder="默认账户密码,登录时修改" autocomplete="off" show-password
-              disabled></el-input>
-          </el-form-item>
-        </el-col>
-
-        <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
-          <el-form-item label="性别" class="gender">
-            <el-radio v-model="forms.gender" label="男">男</el-radio>
-            <el-radio v-model="forms.gender" label="女">女</el-radio>
-            <el-radio v-model="forms.gender" label="无">无</el-radio>
-          </el-form-item>
-        </el-col>
-        <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
-          <el-form-item label="状态">
-            <el-switch v-model="forms.isEnabled" active-color="#13ce66" inactive-color="#ff4949" active-text="启用"
-              inactive-text="禁用" style="margin-left: 10px">
-            </el-switch>
-          </el-form-item>
-        </el-col>
-        <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
-          <el-form-item label="排序号">
-            <el-input-number v-model="forms.sortCode" :min="1" :max="9999999" label="排序号"></el-input-number>
-          </el-form-item>
-        </el-col>
-      </el-row>
-    </el-form>
-  </static-dialog>
+              <el-tree-select v-model="forms.departmentID" :data="departments" check-strictly
+                :render-after-expand="false" />
+            </el-form-item>
+          </el-col>
+
+          <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+            <el-form-item label="用户账户" prop="account">
+              <el-input v-model="forms.account" autocomplete="off"></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+            <el-form-item label="姓名" prop="realName">
+              <el-input v-model="forms.realName" autocomplete="off"></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+            <el-form-item label="手机号" prop="mobile">
+              <el-input v-model="forms.mobile" autocomplete="off"></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+            <el-form-item label="生日">
+              <el-date-picker v-model="forms.birthday" type="date" placeholder="选择生日" format="YYYY-MM-DD"
+                :editable="false">
+              </el-date-picker>
+            </el-form-item>
+          </el-col>
+
+          <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" v-if="!forms.id">
+            <el-form-item label="密码" prop="password">
+              <el-input v-model="forms.password" placeholder="默认账户密码,登录时修改" autocomplete="off" show-password
+                disabled></el-input>
+            </el-form-item>
+          </el-col>
+
+          <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+            <el-form-item label="性别" class="gender">
+              <el-radio v-model="forms.gender" label="男">男</el-radio>
+              <el-radio v-model="forms.gender" label="女">女</el-radio>
+              <el-radio v-model="forms.gender" label="无">无</el-radio>
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+            <el-form-item label="状态">
+              <el-switch v-model="forms.isEnabled" active-color="#13ce66" inactive-color="#ff4949" active-text="启用"
+                inactive-text="禁用" style="margin-left: 10px">
+              </el-switch>
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+            <el-form-item label="排序号">
+              <el-input-number v-model="forms.sortCode" :min="1" :max="9999999" label="排序号"></el-input-number>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+    </static-dialog>
+
+    <div class="dialog">
+      <resetPwdDialog ref="resetPwdRef" :visible="resetDialogVisible" :user="currRow"></resetPwdDialog>
+    </div>
 
-  <div class="dialog">
-    <resetPwdDialog :visible="resetDialogVisible" :user="currRow"></resetPwdDialog>
-  </div>
+    <static-dialog ref="roleDialog" width="900px" class="dialog" title="用户角色分配" :ok="submitRole">
+      <roleSelect ref="roleSelect"></roleSelect>
+    </static-dialog>
+
+    <static-dialog ref="relationDialog" class="dialog" title="关联旅行社" :ok="relationSubmit" width="640">
+      <el-form :model="{ agencyId: relationAgencyId }" label-width="80px">
+        <el-form-item label="用户" prop="userId">
+          <el-input v-model="currRow.account" disabled></el-input>
+        </el-form-item>
+        <el-form-item label="旅行社" prop="agencyId">
+          <el-select v-model="relationAgencyID" filterable>
+            <el-option v-for="item in agencyOptions" :key="item.id" :label="item.agencyName" :value="item.id">
+            </el-option>
+          </el-select>
+        </el-form-item>
+      </el-form>
+    </static-dialog>
+  </el-card>
 
-  <static-dialog ref="roleDialog" width="900px" class="dialog" title="用户角色分配" :ok="submitRole">
-    <roleSelect ref="roleSelect"></roleSelect>
-  </static-dialog>
 </template>
 <script>
-import { fetchUsers, delUsers, submitUser, fetchRelationByGlobalId, submitRelationByGlobalId } from "@/api/sys";
+import {
+  currentUser,
+  submitRelationByGlobalId,
+  submitRelationByObjectId,
+  fetchRelationByGlobalId,
+  fetchRelationByObjectId,
+  fetchUsers,
+  delUsers,
+  submitUser,
+} from "@/api/sys";
+import { getTravelAgencies } from '@/api/travelAgency';
 import StaticDialog from "@/components/static-dialog.vue";
 import StaticTable from "@/components/static-table.vue";
 import resetPwdDialog from "@/views/sys/user/reset.vue";
 import roleSelect from "@/views/sys/role/select.vue";
+import store from "@/store";
+
 export default {
   name: "User",
   components: { StaticDialog, StaticTable, resetPwdDialog, roleSelect },
   data() {
     return {
+      agencyOptions: [],
+      relationAgencyID: '',
       querys: {
         keyword: "",
         columns: [
           { type: "index", label: "序号" },
           { type: 'hidden', prop: "companyID", label: "公司ID", sortable: true, width: "110", },
-          { type: 'hidden', prop: "departmentID", label: "部门ID", sortable: true, width: "110", },
-          { prop: "account", label: "账户", sortable: true, searchable: true, width: "110", },
-          { prop: "realName", label: "姓名", width: "110", sortable: true, searchable: true, },
+          { type: 'hidden', prop: "departmentID", label: "部门ID", sortable: true, minWdth: "110", },
+          { prop: "account", label: "账户", sortable: true, searchable: true, minWdth: "110", },
+          { prop: "realName", label: "姓名", minWdth: "110", sortable: true, searchable: true, },
           { prop: "mobile", label: "手机号", sortable: true, searchable: true, width: "110", },
           { prop: "gender", label: "性别", width: "90", sortable: true, searchable: true, },
           { type: "template", prop: "birthday", label: "生日", sortable: true, width: "120", },
@@ -175,7 +203,7 @@ export default {
           { prop: "sortCode", label: "排序号", sortable: true, width: "100", },
           { prop: "loginDate", label: "最后登录时间", width: "180" },
           { prop: "createDate", label: "创建时间", width: "180" },
-          { type: "toolbar", label: "操作", width: "120" },
+          { type: "toolbar", label: "操作", width: "220" },
         ],
       },
       pager: {
@@ -215,9 +243,8 @@ export default {
   mounted() {
     this.fetchs();
 
-    let that = this;
     this.$kaung.companys().then((res) => {
-      that.companys = res;
+      this.companys = res;
     });
   },
   methods: {
@@ -235,21 +262,20 @@ export default {
       this.$refs.dialog.toggle();
     },
     del() {
-      let that = this;
       this.$confirm("此操作将删除本页选择数据, 是否继续?", "提示", { confirmButtonText: "确定", cancelButtonText: "取消", type: "warning", })
         .then(() => {
-          delUsers(that.currRow.id).then((res) => {
+          delUsers(this.currRow.id).then((res) => {
             if (res.code === 200) {
-              that.$message({
+              this.$message({
                 type: "success",
                 message: "删除成功",
               });
-              that.fetchs();
+              this.fetchs();
             }
           });
         })
         .catch(() => {
-          that.$message({ type: "info", message: "删除失败", });
+          this.$message({ type: "info", message: "删除失败", });
         });
     },
     opened() {
@@ -305,20 +331,18 @@ export default {
       });
     },
     submit() {
-      let that = this;
-
       this.$refs.forms.validate((valid) => {
         if (!valid) return;
 
         submitUser(this.forms).then((res) => {
           if (res.code === 200) {
-            that.$message({
+            this.$message({
               type: "success",
               message: res.content,
             });
 
-            that.$refs.dialog.toggle();
-            that.fetchs();
+            this.$refs.dialog.toggle();
+            this.fetchs();
           }
         });
       });
@@ -342,7 +366,7 @@ export default {
 
     reset() {
       if (this.currRow) {
-        this.resetDialogVisible = true;
+        this.$refs.resetPwdRef.open();
       } else {
         this.$message({
           type: "info",
@@ -352,10 +376,9 @@ export default {
     },
 
     fetchRoleData(globalId) {
-      var that = this;
       fetchRelationByGlobalId('user-role', globalId).then((res) => {
-        that.checkedKeys = res.data;
-        that.$refs.roleSelect.setCheckedKeys(res.data);
+        this.checkedKeys = res.data;
+        this.$refs.roleSelect.setCheckedKeys(res.data);
       });
     },
     openRole(row) {
@@ -376,16 +399,70 @@ export default {
         }
       });
     },
-
+    getCurrentUser() {
+      currentUser().then((res) => {
+        store.commit("setUserInfo", res);
+        console.log(this.$store.getters.getUserInfo);
+      });
+    },
 
     companyChange(companyID) {
       if (!companyID) return;
 
-      var that = this;
       this.$kaung.departments(companyID).then((res) => {
-        that.departments = res;
+        this.departments = res;
       });
-    }
+    },
+    getTravelAgencies() {
+      getTravelAgencies({
+        keyword: "",
+        columns: [
+          { label: "旅行社名称", prop: "agencyName" },
+          { label: "联系人", prop: "contact" },
+          { label: "手机", prop: "phone" },
+          { label: "邮箱", prop: "email" },
+          { label: "地址", prop: "address" },
+          { label: "备注", prop: "remark" }
+        ],
+        rows: 1000,
+      }).then((res) => {
+        this.agencyOptions = res.data?.data || [];
+      });
+    },
+    fetchAgencyRelation() {
+      fetchRelationByObjectId('Agency', this.currRow.id).then((res) => {
+        if (res.data && res.data.length > 0) {
+          this.relationAgencyID = res.data[0];
+        } else {
+          this.relationAgencyID = '';
+        }
+      });
+    },
+    async openRelation(row) {
+      this.currRow = row;
+      this.getTravelAgencies();
+      this.fetchAgencyRelation();
+      this.$refs.relationDialog.toggle();
+    },
+    relationSubmit() {
+      if (!this.relationAgencyID) {
+        this.$message({ type: "info", message: "请选择旅行社", });
+        return;
+      }
+
+      submitRelationByObjectId([this.relationAgencyID], 'Agency', this.currRow.id).then((res) => {
+        if (res.code === 200) {
+          this.$message({
+            type: "success",
+            message: res.content,
+          });
+          this.getCurrentUser();
+          setTimeout(() =>{
+            this.$refs.relationDialog.toggle();  //关闭弹出框
+          }, 500);
+        }
+      });
+    },
   },
 };
 </script>

+ 14 - 2
src/views/sys/user/reset.vue

@@ -1,6 +1,6 @@
 <template>
   <div class="static-dialog load-dialog">
-    <el-dialog :title="title" v-model="visible" :show-close="false" :close-on-click-modal="false" destroy-on-close
+    <el-dialog :title="title" append-to-body v-model="showDialog" :show-close="false" :close-on-click-modal="false" destroy-on-close
       top="5vh" center style="width:95%; max-width:560px;">
       <el-form :model="forms" :rules="rules" ref="forms" label-width="100px" size="large">
         <el-row>
@@ -31,7 +31,7 @@
 
       <template #footer>
         <span class="dialog-footer">
-          <el-button @click="visible = false" size="large">取 消</el-button>
+          <el-button @click="showDialog = false" size="large">取 消</el-button>
           <el-button type="primary" @click="resetPwd()" size="large">确 定</el-button>
         </span>
       </template>
@@ -63,6 +63,7 @@ export default {
   },
   data() {
     return {
+      showDialog: false,
       forms: {},
       rules: {
         oldpassword: [
@@ -77,7 +78,18 @@ export default {
       },
     };
   },
+  watch: {
+    visible(val) {
+      this.showDialog = val;
+    },
+    showDialog(val) {
+      this.$emit("update:visible", val);
+    },
+  },
   methods: {
+    open() {
+      this.showDialog = true;
+    },
     resetPwd() {
       this.forms.id = "";
       if (this.user && this.user.id) this.forms.id = this.user.id;

+ 5 - 2
src/views/travelAgency/index.vue

@@ -58,7 +58,8 @@
       @current-change="pageHandler">
     </el-pagination>
 
-    <el-dialog :title="`${isAdd ? '新增' : '编辑'}旅行社信息`" width="600px" destroy-on-close v-model="formDialogVisible" @close="close">
+    <el-dialog :title="`${isAdd ? '新增' : '编辑'}旅行社信息`" width="600px" destroy-on-close v-model="formDialogVisible"
+      @close="close">
       <el-form :model="formData" :rules="formRules" ref="formRef" :label-width="formLabelWidth">
         <el-row :gutter="10">
           <el-col :span="24">
@@ -269,7 +270,9 @@ export default {
     add(row) {
       this.isAdd = true;
       this.formDialogVisible = true;
-      this.formData = {};
+      this.formData = {
+        status: "Active",
+      };
     },
     handleLicenseSuccess(res) {
       this.formData.licenseImageUrl = res.url;

+ 4 - 1
vue.config.js

@@ -49,6 +49,8 @@ module.exports = {
         maxAssetSize: 30000000,
       };
     }
+
+    config.devtool = 'source-map';
   },
   devServer: {
     // allowedHosts: [
@@ -63,7 +65,8 @@ module.exports = {
     // },
     proxy: {
       '/api': {
-        target: 'http://kaung.cn:7001',
+        // target: 'http://kaung.cn:7001',
+        target: 'https://ljyx.hhtrip.com.cn',
         changeOrigin: true,
         pathRewrite: {
           '^/api': '',