From a185d20af1e8026839b98ffc937a884170fb5a56 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E7=A3=B7=E5=8F=B6?=
 <14103883+leaf-phos@user.noreply.gitee.com>
Date: Sat, 23 Nov 2024 15:16:52 +0800
Subject: [PATCH] =?UTF-8?q?=E5=BA=97=E9=93=BA=E5=91=98=E5=B7=A5=E3=80=81?=
 =?UTF-8?q?=E9=80=80=E6=AC=BE=E6=B5=81=E7=A8=8B=E4=BC=98=E5=8C=96?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/api/app/user.js                           |  13 ++
 src/api/mch/storeStaff.js                     |  44 ++++++
 .../Business/SmUser/UserSearchInput.vue       |  75 +++++++++
 src/router/mchRouter.js                       |  11 ++
 src/utils/constants.js                        |   2 +
 src/utils/mixins.js                           |   2 +-
 src/views/mch/device/index.vue                |  16 +-
 src/views/mch/store/detail.vue                |   2 +-
 src/views/mch/storeStaff/index.vue            | 146 ++++++++++++++++++
 .../components/StoreStaffEditDialog.vue       | 102 ++++++++++--
 src/views/ss/storeStaff/index.vue             |  22 +--
 11 files changed, 404 insertions(+), 31 deletions(-)
 create mode 100644 src/api/mch/storeStaff.js
 create mode 100644 src/components/Business/SmUser/UserSearchInput.vue
 create mode 100644 src/views/mch/storeStaff/index.vue

diff --git a/src/api/app/user.js b/src/api/app/user.js
index f72911f..1a275d5 100644
--- a/src/api/app/user.js
+++ b/src/api/app/user.js
@@ -15,3 +15,16 @@ export function appUpdateUserSetting(data) {
     data
   })
 }
+
+// 根据精准手机号获取用户信息
+export function appGetByEqPhone(eqPhonenumber) {
+  return request({
+    url: "/app/user/getByEqPhone",
+    method: 'get',
+    params: {
+      eqPhonenumber
+    }
+  })
+}
+
+
diff --git a/src/api/mch/storeStaff.js b/src/api/mch/storeStaff.js
new file mode 100644
index 0000000..1be0ccc
--- /dev/null
+++ b/src/api/mch/storeStaff.js
@@ -0,0 +1,44 @@
+import request from '@/utils/request'
+
+// 查询店铺员工列表
+export function mchListStoreStaff(query) {
+  return request({
+    url: '/mch/storeStaff/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询店铺员工详细
+export function mchGetStoreStaff(employId) {
+  return request({
+    url: '/mch/storeStaff/' + employId,
+    method: 'get'
+  })
+}
+
+// 新增店铺员工
+export function mchAddStoreStaff(data) {
+  return request({
+    url: '/mch/storeStaff',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改店铺员工
+export function mchUpdateStoreStaff(data) {
+  return request({
+    url: '/mch/storeStaff',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除店铺员工
+export function mchDelStoreStaff(employId) {
+  return request({
+    url: '/mch/storeStaff/' + employId,
+    method: 'delete'
+  })
+}
diff --git a/src/components/Business/SmUser/UserSearchInput.vue b/src/components/Business/SmUser/UserSearchInput.vue
new file mode 100644
index 0000000..20b297c
--- /dev/null
+++ b/src/components/Business/SmUser/UserSearchInput.vue
@@ -0,0 +1,75 @@
+<template>
+  <el-select
+    style="width: 100%"
+    v-model="val"
+    remote
+    :remote-method="getOptions"
+    filterable
+    reserve-keyword
+    :placeholder="placeholder"
+    :loading="loading"
+  >
+    <el-option
+      v-for="item of options"
+      :value="item.value"
+      :label="item.label"
+      :key="item.value"
+    />
+  </el-select>
+</template>
+
+<script>
+import { appGetByEqPhone } from '@/api/app/user'
+
+export default {
+  name: "UserSearchInput",
+  props: {
+    value: {
+      type: String,
+      default: null,
+    },
+    placeholder: {
+      type: String,
+      default: "请输入用户手机号搜索"
+    },
+    initOptions: {
+      type: Array,
+      default: () => ([])
+    }
+  },
+  data() {
+    return {
+      options: [],
+      loading: false,
+    }
+  },
+  computed: {
+    val: {
+      set(val) {
+        this.$emit('input', val);
+      },
+      get() {
+        return this.value;
+      }
+    }
+  },
+  created() {
+    console.log(this.initOptions);
+    this.options = this.initOptions;
+  },
+  methods: {
+    getOptions(keyword) {
+      this.loading = true;
+      appGetByEqPhone(keyword).then(res => {
+        if (res.code === 200 && res.data != null) {
+          this.options = [{value: res.data.userId, label: res.data.realOrUserName}];
+        } else {
+          this.options = [];
+        }
+      }).finally(() => {
+        this.loading = false;
+      })
+    }
+  }
+}
+</script>
diff --git a/src/router/mchRouter.js b/src/router/mchRouter.js
index d279718..e06e524 100644
--- a/src/router/mchRouter.js
+++ b/src/router/mchRouter.js
@@ -25,6 +25,17 @@ export const mchRoutes = [
           icon: 'store'
         }
       },
+      {
+        path: 'storeStaff',
+        component: () => import('../views/mch/storeStaff'),
+        hidden: false,
+        name: "MyStoreStaff",
+        meta: {
+          noCache: false,
+          title: '店铺员工',
+          icon: 'agent'
+        }
+      },
       {
         path: 'store/:storeId',
         component: () => import('../views/mch/store/detail.vue'),
diff --git a/src/utils/constants.js b/src/utils/constants.js
index 1ca08af..75a2268 100644
--- a/src/utils/constants.js
+++ b/src/utils/constants.js
@@ -8,6 +8,8 @@ export const views = {
   withdraw: 'withdraw', // 提现
   recharge: 'recharge', // 充值订单
   agent: 'agent', // 代理商
+
+  mchStore: 'mchStore', // 商户中心的店铺
 }
 
 // 代理商视图
diff --git a/src/utils/mixins.js b/src/utils/mixins.js
index a1f07aa..59a2ef3 100644
--- a/src/utils/mixins.js
+++ b/src/utils/mixins.js
@@ -160,7 +160,7 @@ export const $recharge = {
     },
     canRefund() {
       return (row) => {
-        return row.status === '2';
+        return row.status === '2' && row.isFinished;
       }
     },
     canClose() {
diff --git a/src/views/mch/device/index.vue b/src/views/mch/device/index.vue
index 55dcfc7..ddae4df 100644
--- a/src/views/mch/device/index.vue
+++ b/src/views/mch/device/index.vue
@@ -168,11 +168,6 @@
 
 <script>
 import {
-  listDevice,
-  getDevice,
-  addDevice,
-  updateDevice,
-  logicDelDevice,
   updateDeviceSn,
   batchUpdateModel, updateDeviceServiceRate
 } from '@/api/system/device'
@@ -197,6 +192,12 @@ export default {
   mixins: [$serviceType],
   components: { DeviceTable, DeviceLink, StoreLink, UserLink, ModelDialog, UserInput, StoreInput, SnInput, QrCode, SmUserSelect, ModelSelect},
   dicts: ['sm_device_online_status', 'sm_device_status', 'sm_device_outage_way','sm_device_notice_way', 'service_type', 'time_unit'],
+  props: {
+    query: {
+      type: Object,
+      default: () => ({})
+    }
+  },
   data() {
     return {
       // 是否展示选择型号弹窗
@@ -268,6 +269,11 @@ export default {
     },
   },
   created() {
+    this.queryParams = {
+      ...this.queryParams,
+      ...this.query
+    }
+
     this.getList();
   },
   methods: {
diff --git a/src/views/mch/store/detail.vue b/src/views/mch/store/detail.vue
index d5503db..61fb06a 100644
--- a/src/views/mch/store/detail.vue
+++ b/src/views/mch/store/detail.vue
@@ -96,7 +96,7 @@
     <el-card class="box-card">
       <el-tabs>
         <el-tab-pane label="设备列表" :lazy="true">
-          <my-device :store-id="store.storeId"/>
+          <my-device v-if="store.storeId != null" :query="{storeId: store.storeId}"/>
         </el-tab-pane>
         <el-tab-pane label="订单列表" :lazy="true">
           <mch-recharge :query="{storeId: store.storeId}" :view="views.store"/>
diff --git a/src/views/mch/storeStaff/index.vue b/src/views/mch/storeStaff/index.vue
new file mode 100644
index 0000000..7479830
--- /dev/null
+++ b/src/views/mch/storeStaff/index.vue
@@ -0,0 +1,146 @@
+<template>
+  <div class="app-container">
+    <store-staff-table
+      ref="table"
+      @selection-change="handleSelectionChange"
+      :query="query"
+      :list-api="mchListStoreStaff"
+    >
+      <template #table-operator>
+        <el-col :span="1.5">
+          <el-button
+            type="primary"
+            plain
+            icon="el-icon-plus"
+            size="mini"
+            @click="handleAdd"
+          >新增</el-button>
+        </el-col>
+        <el-col :span="1.5">
+          <el-button
+            type="danger"
+            plain
+            icon="el-icon-delete"
+            size="mini"
+            :disabled="multiple"
+            @click="handleDelete"
+          >删除</el-button>
+        </el-col>
+      </template>
+      <template v-slot:row-operator="scope">
+        <el-button
+          size="mini"
+          type="text"
+          icon="el-icon-edit"
+          @click="handleUpdate(scope.row)"
+        >修改</el-button>
+        <el-button
+          size="mini"
+          type="text"
+          icon="el-icon-delete"
+          @click="handleDelete(scope.row)"
+        >删除</el-button>
+      </template>
+    </store-staff-table>
+
+    <!-- 添加或修改店铺员工对话框 -->
+    <store-staff-edit-dialog
+      :show.sync="open"
+      :view="view"
+      :employ-id="row.employId"
+      @success="getList"
+      :init-form="{storeId: query.storeId}"
+      user-input-type="search"
+      :update-api="mchUpdateStoreStaff"
+      :add-api="mchAddStoreStaff"
+      :load-api="mchGetStoreStaff"
+    />
+
+  </div>
+</template>
+
+<script>
+import { $showColumns, $view } from '@/utils/mixins'
+import BooleanTag from '@/components/BooleanTag/index.vue'
+import StoreInput from '@/components/Business/Store/StoreInput.vue'
+import UserInput from '@/components/Business/SmUser/UserInput.vue'
+import UserLink from '@/components/Business/SmUser/UserLink.vue'
+import StoreLink from '@/components/Business/Store/StoreLink.vue'
+import StoreStaffTable from '@/views/ss/storeStaff/components/StoreStaffTable.vue'
+import StoreStaffEditDialog from '@/views/ss/storeStaff/components/StoreStaffEditDialog.vue'
+import {
+  mchAddStoreStaff,
+  mchDelStoreStaff,
+  mchGetStoreStaff,
+  mchListStoreStaff,
+  mchUpdateStoreStaff
+} from '@/api/mch/storeStaff'
+
+export default {
+  name: "StoreStaff",
+  components: { StoreStaffEditDialog, StoreStaffTable, StoreLink, UserLink, UserInput, StoreInput, BooleanTag },
+  mixins: [$showColumns, $view],
+  dicts: ['store_staff_permissions', 'store_staff_role'],
+  props: {
+    query: {
+      type: Object,
+      default: () => {
+        return {}
+      }
+    }
+  },
+  data() {
+    return {
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      row: {},
+      open: false,
+    };
+  },
+  methods: {
+    mchGetStoreStaff,
+    mchAddStoreStaff,
+    mchUpdateStoreStaff,
+    mchListStoreStaff,
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.employId)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.row = {};
+      this.open = true;
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.row = row;
+      this.open = true;
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const employIds = row.employId || this.ids;
+      this.$modal.confirm('是否确认删除店铺员工编号为"' + employIds + '"的数据项?').then(function() {
+        return mchDelStoreStaff(employIds);
+      }).then(() => {
+        this.getList();
+        this.$modal.msgSuccess("删除成功");
+      }).catch(() => {});
+    },
+    getList() {
+      this.$refs.table.getList();
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      this.download('ss/storeStaff/export', {
+        ...this.queryParams
+      }, `storeStaff_${new Date().getTime()}.xlsx`)
+    }
+  }
+};
+</script>
diff --git a/src/views/ss/storeStaff/components/StoreStaffEditDialog.vue b/src/views/ss/storeStaff/components/StoreStaffEditDialog.vue
index f1d516a..7a960db 100644
--- a/src/views/ss/storeStaff/components/StoreStaffEditDialog.vue
+++ b/src/views/ss/storeStaff/components/StoreStaffEditDialog.vue
@@ -1,12 +1,15 @@
 <template>
-  <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
-    <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+  <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body @open="onOpen">
+    <el-form ref="form" :model="form" :rules="rules" label-width="80px" v-loading="loading">
       <el-form-item label="店铺" prop="storeId">
-        <store-input v-model="form.storeId" :disabled="hasView(views.store)"/>
+        <store-input v-model="form.storeId" :disabled="hasView([views.store, views.mchStore])"/>
       </el-form-item>
-      <el-form-item label="用户" prop="userId">
+      <el-form-item label="用户" prop="userId" v-if="userInputType === 'dialog'">
         <user-input v-model="form.userId"/>
       </el-form-item>
+      <el-form-item label="用户" prop="userId" v-else-if="userInputType === 'search'">
+        <user-search-input v-if="open && !loading" v-model="form.userId" :init-options="initUserSearchOptions"/>
+      </el-form-item>
       <el-form-item label="备注名" prop="remark">
         <el-input v-model="form.remark" placeholder="请输入备注名" maxlength="200" show-word-limit/>
       </el-form-item>
@@ -51,21 +54,60 @@
   </el-dialog>
 </template>
 <script>
-import { StoreStaffRole } from '@/utils/constants'
-import { addStoreStaff, updateStoreStaff } from '@/api/ss/storeStaff'
+import { StoreStaffRole, UserType } from '@/utils/constants'
+import { addStoreStaff, getStoreStaff, updateStoreStaff } from '@/api/ss/storeStaff'
 import StoreInput from '@/components/Business/Store/StoreInput.vue'
 import UserInput from '@/components/Business/SmUser/UserInput.vue'
 import { $view } from '@/utils/mixins'
+import { mapGetters } from 'vuex'
+import UserSearchInput from '@/components/Business/SmUser/UserSearchInput.vue'
 
 export default {
   name: "StoreStaffEditDialog",
   mixins: [$view],
   dicts: ['store_staff_permissions', 'store_staff_role'],
-  components: { UserInput, StoreInput },
+  components: { UserSearchInput, UserInput, StoreInput },
+  props: {
+    // ID
+    employId: {
+      type: String,
+      default: null,
+    },
+    show: {
+      type: Boolean,
+      default: false
+    },
+    initForm: {
+      type: Object,
+      default: () => ({})
+    },
+    // 用户的输入方式:dialog 弹窗选择,search 搜索选择
+    userInputType: {
+      type: String,
+      default: "dialog"
+    },
+    // 更新API
+    updateApi: {
+      type: Function,
+      default: updateStoreStaff
+    },
+    // 新增API
+    addApi: {
+      type: Function,
+      default: addStoreStaff
+    },
+    // 加载API
+    loadApi: {
+      type: Function,
+      default: getStoreStaff
+    }
+  },
   data() {
     return {
       // 表单参数
       form: {},
+      title: null,
+      loading: false,
       // 表单校验
       rules: {
         storeId: [
@@ -83,7 +125,39 @@ export default {
       }
     }
   },
+  computed: {
+    initUserSearchOptions() {
+      return [{value: this.form.userId, label: this.form.userName}]
+    },
+    UserType() {
+      return UserType
+    },
+    ...mapGetters(['userType']),
+    open: {
+      get() {
+        return this.show;
+      },
+      set(val) {
+        this.$emit('update:show', val)
+      }
+    }
+  },
+  created() {
+    this.reset();
+  },
   methods: {
+    onOpen() {
+      if (this.employId != null) {
+        this.loading = true;
+        this.loadApi(this.employId).then(res => {
+          this.form = res.data;
+        }).finally(() => {
+          this.loading = false;
+        })
+      } else {
+        this.reset();
+      }
+    },
     // 取消按钮
     cancel() {
       this.open = false;
@@ -93,16 +167,14 @@ export default {
     reset() {
       this.form = {
         employId: null,
-        storeId: this.query.storeId,
+        storeId: null,
         userId: null,
         remark: null,
         role: StoreStaffRole.STAFF,
         point: 0,
         enabled: true,
         permissions: [],
-        createTime: null,
-        createBy: null,
-        createId: null
+        ...this.initForm
       };
       this.resetForm("form");
     },
@@ -111,16 +183,16 @@ export default {
       this.$refs["form"].validate(valid => {
         if (valid) {
           if (this.form.employId != null) {
-            updateStoreStaff(this.form).then(response => {
+            this.updateApi(this.form).then(response => {
               this.$modal.msgSuccess("修改成功");
               this.open = false;
-              this.getList();
+              this.$emit('success')
             });
           } else {
-            addStoreStaff(this.form).then(response => {
+            this.addApi(this.form).then(response => {
               this.$modal.msgSuccess("新增成功");
               this.open = false;
-              this.getList();
+              this.$emit('success')
             });
           }
         }
diff --git a/src/views/ss/storeStaff/index.vue b/src/views/ss/storeStaff/index.vue
index 98bff50..f2645ed 100644
--- a/src/views/ss/storeStaff/index.vue
+++ b/src/views/ss/storeStaff/index.vue
@@ -53,7 +53,13 @@
     </store-staff-table>
 
     <!-- 添加或修改店铺员工对话框 -->
-    <store-staff-edit-dialog :view="view" :employ-id="row.employId"/>
+    <store-staff-edit-dialog
+      :show.sync="open"
+      :view="view"
+      :employ-id="row.employId"
+      @success="getList"
+      :init-form="{storeId: query.storeId}"
+    />
 
   </div>
 </template>
@@ -92,7 +98,7 @@ export default {
       // 非多个禁用
       multiple: true,
       row: {},
-      open: false
+      open: false,
     };
   },
   methods: {
@@ -109,13 +115,8 @@ export default {
     },
     /** 修改按钮操作 */
     handleUpdate(row) {
-      this.reset();
-      const employId = row.employId || this.ids
-      getStoreStaff(employId).then(response => {
-        this.form = response.data;
-        this.open = true;
-        this.title = "修改店铺员工";
-      });
+      this.row = row;
+      this.open = true;
     },
     /** 删除按钮操作 */
     handleDelete(row) {
@@ -127,6 +128,9 @@ export default {
         this.$modal.msgSuccess("删除成功");
       }).catch(() => {});
     },
+    getList() {
+      this.$refs.table.getList();
+    },
     /** 导出按钮操作 */
     handleExport() {
       this.download('ss/storeStaff/export', {