From db3d5319edc7d50837d115b3c8b629aa732c29a5 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: Fri, 15 Nov 2024 10:45:37 +0800
Subject: [PATCH] =?UTF-8?q?=E5=BA=97=E9=93=BA=E5=91=98=E5=B7=A5?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/api/ss/storeStaff.js                      |  44 ++++
 src/components/Business/SmUser/UserInput.vue  |   2 +-
 .../Business/SmUser/smUserDialog.vue          |  21 +-
 src/components/LineField/index.vue            |   4 +-
 src/utils/constants.js                        |  14 +-
 src/views/ss/store/detail.vue                 |   8 +-
 src/views/ss/store/index.vue                  |  15 +-
 .../components/StoreStaffEditDialog.vue       | 131 ++++++++++
 .../storeStaff/components/StoreStaffTable.vue | 247 ++++++++++++++++++
 src/views/ss/storeStaff/index.vue             | 138 ++++++++++
 src/views/system/device/detail.vue            |  99 ++++---
 src/views/system/smUser/detail.vue            |   5 +-
 12 files changed, 670 insertions(+), 58 deletions(-)
 create mode 100644 src/api/ss/storeStaff.js
 create mode 100644 src/views/ss/storeStaff/components/StoreStaffEditDialog.vue
 create mode 100644 src/views/ss/storeStaff/components/StoreStaffTable.vue
 create mode 100644 src/views/ss/storeStaff/index.vue

diff --git a/src/api/ss/storeStaff.js b/src/api/ss/storeStaff.js
new file mode 100644
index 0000000..d936cd9
--- /dev/null
+++ b/src/api/ss/storeStaff.js
@@ -0,0 +1,44 @@
+import request from '@/utils/request'
+
+// 查询店铺员工列表
+export function listStoreStaff(query) {
+  return request({
+    url: '/ss/storeStaff/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询店铺员工详细
+export function getStoreStaff(employId) {
+  return request({
+    url: '/ss/storeStaff/' + employId,
+    method: 'get'
+  })
+}
+
+// 新增店铺员工
+export function addStoreStaff(data) {
+  return request({
+    url: '/ss/storeStaff',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改店铺员工
+export function updateStoreStaff(data) {
+  return request({
+    url: '/ss/storeStaff',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除店铺员工
+export function delStoreStaff(employId) {
+  return request({
+    url: '/ss/storeStaff/' + employId,
+    method: 'delete'
+  })
+}
diff --git a/src/components/Business/SmUser/UserInput.vue b/src/components/Business/SmUser/UserInput.vue
index 50cdcd3..3c9a4cf 100644
--- a/src/components/Business/SmUser/UserInput.vue
+++ b/src/components/Business/SmUser/UserInput.vue
@@ -57,7 +57,7 @@ export default {
     // 展示值的属性
     showProp: {
       type: String,
-      default: 'userName'
+      default: 'realOrUserName'
     },
     // 选择的属性值
     prop: {
diff --git a/src/components/Business/SmUser/smUserDialog.vue b/src/components/Business/SmUser/smUserDialog.vue
index 246a8f5..3e96f24 100644
--- a/src/components/Business/SmUser/smUserDialog.vue
+++ b/src/components/Business/SmUser/smUserDialog.vue
@@ -4,7 +4,7 @@
              :append-to-body="true">
     <el-form  size="small" :inline="true" label-width="68px">
       <el-form-item label="用户名">
-        <el-input v-model="searchForm.userName" clearable @keyup.enter.native="onSearch" placeholder="请输入用户名"/>
+        <el-input v-model="searchForm.realOrUserName" clearable @keyup.enter.native="onSearch" placeholder="请输入用户名"/>
       </el-form-item>
       <el-form-item label="手机号">
         <el-input v-model="searchForm.phonenumber" type="number" :maxlength="11" show-word-limit clearable @keyup.enter.native="onSearch" placeholder="请输入手机号"/>
@@ -26,9 +26,19 @@
     >
       <el-table-column align="center" type="selection" v-if="multiple"></el-table-column>
       <el-table-column label="#" type="index" align="center"></el-table-column>
-      <el-table-column label="用户名" align="center" prop="userName"></el-table-column>
-      <el-table-column label="昵称" align="center" prop="nickName"></el-table-column>
-      <el-table-column label="手机号" align="center" prop="phonenumber"></el-table-column>
+      <el-table-column label="用户名" align="center" prop="realOrUserName"/>
+      <el-table-column label="实名" align="center" prop="isReal">
+        <template slot-scope="d">
+          <boolean-tag :value="d.row.isReal" true-text="已实名" false-text="未实名"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="手机号" align="center" prop="phonenumber"/>
+      <el-table-column label="类型" align="center" prop="type">
+        <template slot-scope="d">
+          <dict-tag :value="d.row.type" :options="dict.type.sm_user_type"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="备注" align="center" prop="remark"/>
     </el-table>
     <pagination
       :limit.sync="searchForm.pageSize"
@@ -45,9 +55,12 @@
 <script>
 import {clone} from "@/utils";
 import {listSmUser} from "@/api/system/smUser";
+import BooleanTag from '@/components/BooleanTag/index.vue'
 
 export default {
   name: "smUserDialog",
+  components: { BooleanTag },
+  dicts: ['sm_user_type'],
   data() {
     return {
       loadTable: false,
diff --git a/src/components/LineField/index.vue b/src/components/LineField/index.vue
index a091974..3f42817 100644
--- a/src/components/LineField/index.vue
+++ b/src/components/LineField/index.vue
@@ -1,7 +1,9 @@
 <template>
   <div class="line-field">
     <div class="label">
-      {{label}}
+      <slot name="label">
+        {{label}}
+      </slot>
     </div>
     <div class="right-box" >
       <slot>
diff --git a/src/utils/constants.js b/src/utils/constants.js
index c06ed34..b0007ae 100644
--- a/src/utils/constants.js
+++ b/src/utils/constants.js
@@ -194,9 +194,10 @@ export const BonusArrivalType = {
   PLATFORM: "1",  // 平台
   AGENT: "2",  // 代理商
   MCH: "3",  // 商户
+  STAFF: "4", // 员工
   // 用户表
   userList() {
-    return [this.AGENT, this.MCH]
+    return [this.AGENT, this.MCH, this.STAFF]
   },
   // 部门表
   deptList() {
@@ -212,3 +213,14 @@ export const ModelTag = {
   GPS: "4", // GPS
   ELE: "5", // 电量
 }
+
+// 店铺员工角色
+export const StoreStaffRole = {
+  OWNER: "1", // 所有者
+  STAFF: "2", // 员工
+}
+
+export const DeviceOnlineStatus = {
+  ONLINE: "1",  // 在线
+  OFFLINE: "0", // 离线
+}
diff --git a/src/views/ss/store/detail.vue b/src/views/ss/store/detail.vue
index e94af52..dd7cb3e 100644
--- a/src/views/ss/store/detail.vue
+++ b/src/views/ss/store/detail.vue
@@ -102,13 +102,14 @@
     <el-card class="box-card">
       <el-tabs>
         <el-tab-pane label="设备列表" :lazy="true">
-<!--          <device-list :store-id="store.storeId"/>-->
           <device v-if="store.storeId != null" :query="{storeId: store.storeId}" :view="views.store"/>
         </el-tab-pane>
         <el-tab-pane label="订单列表" :lazy="true">
-<!--          <recharge-list :store-id="store.storeId"/>-->
           <recharge v-if="store.storeId != null" :query="{storeId: store.storeId}" :view="views.store"/>
         </el-tab-pane>
+        <el-tab-pane label="员工列表" :lazy="true">
+          <store-staff :query="{storeId: store.storeId}" :view="views.store"/>
+        </el-tab-pane>
         <el-tab-pane label="变更记录" :lazy="true">
           <store-apply :query="{storeId: store.storeId}" :view="views.store"/>
         </el-tab-pane>
@@ -133,6 +134,7 @@ import Recharge from '@/views/system/recharge/index.vue'
 import { isEmpty } from '@/utils'
 import deviceData from 'svg-sprite-loader/examples/custom-runtime-generator/build/main'
 import BooleanTag from '@/components/BooleanTag/index.vue'
+import StoreStaff from '@/views/ss/storeStaff/index.vue'
 
 export default {
   name: 'storeDetail',
@@ -144,7 +146,7 @@ export default {
       return views
     }
   },
-  components: { BooleanTag, Recharge, Device, StoreApply, UserLink, StoreRechargeReport, RechargeList, DeviceList, PlaceSearchMap },
+  components: { StoreStaff, BooleanTag, Recharge, Device, StoreApply, UserLink, StoreRechargeReport, RechargeList, DeviceList, PlaceSearchMap },
   dicts: ['ss_store_type', 'store_status'],
   data() {
     return {
diff --git a/src/views/ss/store/index.vue b/src/views/ss/store/index.vue
index 99293a8..af36220 100644
--- a/src/views/ss/store/index.vue
+++ b/src/views/ss/store/index.vue
@@ -139,7 +139,7 @@
         <template slot-scope="d">{{d.row.offlineCount}} 台</template>
       </el-table-column>
       <el-table-column label="创建时间" align="center" prop="createTime" width="180"/>
-      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="180">
         <template slot-scope="scope">
           <el-button
             size="mini"
@@ -147,7 +147,7 @@
             icon="el-icon-view"
             @click="handleView(scope.row)"
             v-hasPermi="['ss:store:detail']"
-          >查看详情</el-button>
+          >详情</el-button>
           <el-button
             size="mini"
             type="text"
@@ -182,7 +182,7 @@
             <image-upload v-model="form.picture" :limit="9"/>
           </form-col>
           <form-col label="所属用户" prop="userId" :span="span">
-            <user-input v-model="form.userId" :query="userQuery" :disabled="hasView(views.user)"/>
+            <user-input v-model="form.userId" :disabled="hasView(views.user)"/>
           </form-col>
           <form-col label="是否在地图展示" prop="show" :span="span" label-width="9em">
             <el-switch v-model="form.show"/>
@@ -348,11 +348,6 @@ export default {
     };
   },
   computed: {
-    userQuery() {
-      return {
-        isMch: true,
-      }
-    },
     formatBusinessTime: {
       set(val) {
         this.form.businessTimeStart = val[0];
@@ -444,7 +439,7 @@ export default {
     handleAdd() {
       this.reset();
       this.open = true;
-      this.title = "添加商户列表";
+      this.title = "添加店铺";
     },
     handleView(row) {
       this.$router.push({
@@ -461,7 +456,7 @@ export default {
       getStore(storeId).then(response => {
         this.form = response.data;
         this.open = true;
-        this.title = "修改商户列表";
+        this.title = "修改店铺";
       });
     },
     /** 提交按钮 */
diff --git a/src/views/ss/storeStaff/components/StoreStaffEditDialog.vue b/src/views/ss/storeStaff/components/StoreStaffEditDialog.vue
new file mode 100644
index 0000000..f1d516a
--- /dev/null
+++ b/src/views/ss/storeStaff/components/StoreStaffEditDialog.vue
@@ -0,0 +1,131 @@
+<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-form-item label="店铺" prop="storeId">
+        <store-input v-model="form.storeId" :disabled="hasView(views.store)"/>
+      </el-form-item>
+      <el-form-item label="用户" prop="userId">
+        <user-input v-model="form.userId"/>
+      </el-form-item>
+      <el-form-item label="备注名" prop="remark">
+        <el-input v-model="form.remark" placeholder="请输入备注名" maxlength="200" show-word-limit/>
+      </el-form-item>
+      <el-form-item label="角色" prop="role">
+        <el-select v-model="form.role" placeholder="请选择角色" style="width: 100%">
+          <el-option
+            v-for="dict in dict.type.store_staff_role"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          ></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="分成比例" prop="point">
+        <el-input-number
+          v-model="form.point"
+          placeholder="请输入分成比例"
+          :min="0"
+          :max="100"
+          style="width: calc(100% - 2em)"
+          controls-position="right"
+        /> %
+      </el-form-item>
+      <el-form-item label="是否启用" prop="enabled">
+        <el-switch v-model="form.enabled" active-text="启用" inactive-text="禁用"/>
+      </el-form-item>
+      <el-form-item label="权限列表" prop="permissions">
+        <el-checkbox-group v-model="form.permissions">
+          <el-checkbox
+            v-for="dict in dict.type.store_staff_permissions"
+            :key="dict.value"
+            :label="dict.value">
+            {{dict.label}}
+          </el-checkbox>
+        </el-checkbox-group>
+      </el-form-item>
+    </el-form>
+    <div slot="footer" class="dialog-footer">
+      <el-button type="primary" @click="submitForm">确 定</el-button>
+      <el-button @click="cancel">取 消</el-button>
+    </div>
+  </el-dialog>
+</template>
+<script>
+import { StoreStaffRole } from '@/utils/constants'
+import { addStoreStaff, 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'
+
+export default {
+  name: "StoreStaffEditDialog",
+  mixins: [$view],
+  dicts: ['store_staff_permissions', 'store_staff_role'],
+  components: { UserInput, StoreInput },
+  data() {
+    return {
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+        storeId: [
+          { required: true, message: "店铺不能为空", trigger: "change" }
+        ],
+        userId: [
+          { required: true, message: "用户不能为空", trigger: "change" }
+        ],
+        point: [
+          { required: true, message: "分成比例不能为空", trigger: "change" }
+        ],
+        enabled: [
+          { required: true, message: "是否启用不能为空", trigger: "change" }
+        ],
+      }
+    }
+  },
+  methods: {
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        employId: null,
+        storeId: this.query.storeId,
+        userId: null,
+        remark: null,
+        role: StoreStaffRole.STAFF,
+        point: 0,
+        enabled: true,
+        permissions: [],
+        createTime: null,
+        createBy: null,
+        createId: null
+      };
+      this.resetForm("form");
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.employId != null) {
+            updateStoreStaff(this.form).then(response => {
+              this.$modal.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addStoreStaff(this.form).then(response => {
+              this.$modal.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+  }
+}
+</script>
diff --git a/src/views/ss/storeStaff/components/StoreStaffTable.vue b/src/views/ss/storeStaff/components/StoreStaffTable.vue
new file mode 100644
index 0000000..3a8a6a2
--- /dev/null
+++ b/src/views/ss/storeStaff/components/StoreStaffTable.vue
@@ -0,0 +1,247 @@
+<template>
+  <div>
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="店铺名称" prop="storeName">
+        <el-input
+          v-model="queryParams.storeName"
+          placeholder="请输入店铺名称"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="用户名称" prop="userName">
+        <el-input
+          v-model="queryParams.userName"
+          placeholder="请输入用户名称"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="备注名" prop="remark">
+        <el-input
+          v-model="queryParams.remark"
+          placeholder="请输入备注名"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="角色" prop="role">
+        <el-select v-model="queryParams.role" placeholder="请选择角色" clearable @change="handleQuery">
+          <el-option
+            v-for="dict in dict.type.store_staff_role"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="是否启用" prop="enabled">
+        <el-radio-group v-model="queryParams.enabled" @change="handleQuery">
+          <el-radio :label="null">全部</el-radio>
+          <el-radio :label="true">已启用</el-radio>
+          <el-radio :label="false">已禁用</el-radio>
+        </el-radio-group>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <slot name="table-operator"></slot>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList" :columns="columns"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="storeStaffList" v-on="$listeners" :default-sort="defaultSort"  @sort-change="onSortChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <template v-for="column of showColumns">
+        <el-table-column
+          :key="column.key"
+          :label="column.label"
+          :prop="column.key"
+          :align="column.align"
+          :min-width="column.minWidth"
+          :sort-orders="orderSorts"
+          :sortable="column.sortable"
+          :show-overflow-tooltip="column.overflow"
+          :width="column.width"
+        >
+          <template slot-scope="d">
+            <template v-if="column.key === 'employId'">
+              {{d.row[column.key]}}
+            </template>
+            <template v-else-if="column.key === 'role'">
+              <dict-tag :options="dict.type.store_staff_role" :value="d.row[column.key]"/>
+            </template>
+            <template v-else-if="column.key === 'permissions'">
+              <dict-tag :options="dict.type.store_staff_permissions" :value="d.row[column.key]"/>
+            </template>
+            <template v-else-if="column.key === 'enabled'">
+              <boolean-tag :value="d.row.enabled"/>
+            </template>
+            <template v-else-if="column.key === 'point'">
+              {{d.row.point | money | defaultValue}} %
+            </template>
+            <template v-else-if="column.key === 'userName'">
+              <user-link :id="d.row.userId" :name="d.row.userName"/>
+            </template>
+            <template v-else-if="column.key === 'storeName'">
+              <store-link :id="d.row.storeId" :name="d.row.storeName"/>
+            </template>
+            <template v-else>
+              {{d.row[column.key] | defaultValue}}
+            </template>
+          </template>
+        </el-table-column>
+      </template>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <slot name="row-operator" :row="scope.row"/>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+  </div>
+</template>
+
+<script>
+import UserLink from '@/components/Business/SmUser/UserLink.vue'
+import BooleanTag from '@/components/BooleanTag/index.vue'
+import StoreLink from '@/components/Business/Store/StoreLink.vue'
+import UserInput from '@/components/Business/SmUser/UserInput.vue'
+import StoreInput from '@/components/Business/Store/StoreInput.vue'
+import { $showColumns, $view } from '@/utils/mixins'
+import { listStoreStaff } from '@/api/ss/storeStaff'
+
+
+// 默认排序字段
+const defaultSort = {
+  prop: "createTime",
+  order: "descending"
+}
+
+export default {
+  name: "StoreStaffTable",
+  components: { StoreLink, UserLink, UserInput, StoreInput, BooleanTag },
+  mixins: [$showColumns, $view],
+  dicts: ['store_staff_permissions', 'store_staff_role'],
+  props: {
+    query: {
+      type: Object,
+      default: () => {
+        return {}
+      }
+    },
+    listApi: {
+      type: Function,
+      default: listStoreStaff
+    }
+  },
+  data() {
+    return {
+      // 字段列表
+      columns: [
+        {key: 'employId', visible: false, label: 'ID', minWidth: null, sortable: true, overflow: false, align: 'center', width: null},
+        {key: 'storeName', visible: true, label: '店铺', minWidth: null, sortable: true, overflow: false, align: 'center', width: null},
+        {key: 'userName', visible: true, label: '用户', minWidth: null, sortable: true, overflow: false, align: 'center', width: null},
+        {key: 'remark', visible: true, label: '备注名', minWidth: null, sortable: true, overflow: false, align: 'center', width: null},
+        {key: 'role', visible: true, label: '角色', minWidth: null, sortable: true, overflow: false, align: 'center', width: null},
+        {key: 'point', visible: true, label: '分成比例', minWidth: null, sortable: true, overflow: false, align: 'center', width: null},
+        {key: 'enabled', visible: true, label: '是否启用', minWidth: null, sortable: true, overflow: false, align: 'center', width: null},
+        {key: 'createBy', visible: true, label: '创建人', minWidth: null, sortable: true, overflow: false, align: 'center', width: null},
+        {key: 'createTime', visible: true, label: '创建时间', minWidth: null, sortable: true, overflow: false, align: 'center', width: "100"},
+        {key: 'permissions', visible: true, label: '权限', minWidth: null, sortable: false, overflow: false, align: 'center', width: "300"},
+      ],
+      // 排序方式
+      orderSorts: ['ascending', 'descending', null],
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 店铺员工表格数据
+      storeStaffList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      defaultSort,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 20,
+        orderByColumn: defaultSort.prop,
+        isAsc: defaultSort.order,
+        employId: null,
+        storeId: null,
+        userId: null,
+        remark: null,
+        role: null,
+        point: null,
+        enabled: null,
+        createId: null
+      },
+    };
+  },
+  created() {
+    this.queryParams = {
+      ...this.queryParams,
+      ...this.query
+    }
+    this.getList();
+  },
+  methods: {
+    /** 当排序按钮被点击时触发 **/
+    onSortChange(column) {
+      if (column.order == null) {
+        this.queryParams.orderByColumn = defaultSort.prop;
+        this.queryParams.isAsc = defaultSort.order;
+      } else {
+        this.queryParams.orderByColumn = column.prop;
+        this.queryParams.isAsc = column.order;
+      }
+      this.getList();
+    },
+    /** 查询店铺员工列表 */
+    getList() {
+      this.loading = true;
+      this.listApi(this.queryParams).then(response => {
+        this.storeStaffList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.employId)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+  }
+};
+</script>
diff --git a/src/views/ss/storeStaff/index.vue b/src/views/ss/storeStaff/index.vue
new file mode 100644
index 0000000..98bff50
--- /dev/null
+++ b/src/views/ss/storeStaff/index.vue
@@ -0,0 +1,138 @@
+<template>
+  <div class="app-container">
+    <store-staff-table ref="table" @selection-change="handleSelectionChange" :query="query">
+      <template #table-operator>
+        <el-col :span="1.5">
+          <el-button
+            type="primary"
+            plain
+            icon="el-icon-plus"
+            size="mini"
+            @click="handleAdd"
+            v-hasPermi="['ss:storeStaff:add']"
+          >新增</el-button>
+        </el-col>
+        <el-col :span="1.5">
+          <el-button
+            type="danger"
+            plain
+            icon="el-icon-delete"
+            size="mini"
+            :disabled="multiple"
+            @click="handleDelete"
+            v-hasPermi="['ss:storeStaff:remove']"
+          >删除</el-button>
+        </el-col>
+        <el-col :span="1.5">
+          <el-button
+            type="warning"
+            plain
+            icon="el-icon-download"
+            size="mini"
+            @click="handleExport"
+            v-hasPermi="['ss:storeStaff:export']"
+          >导出</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)"
+          v-hasPermi="['ss:storeStaff:edit']"
+        >修改</el-button>
+        <el-button
+          size="mini"
+          type="text"
+          icon="el-icon-delete"
+          @click="handleDelete(scope.row)"
+          v-hasPermi="['ss:storeStaff:remove']"
+        >删除</el-button>
+      </template>
+    </store-staff-table>
+
+    <!-- 添加或修改店铺员工对话框 -->
+    <store-staff-edit-dialog :view="view" :employ-id="row.employId"/>
+
+  </div>
+</template>
+
+<script>
+import { listStoreStaff, getStoreStaff, delStoreStaff, addStoreStaff, updateStoreStaff } from "@/api/ss/storeStaff";
+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 { StoreStaffRole } from '@/utils/constants'
+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'
+
+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: {
+    // 多选框选中数据
+    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.reset();
+      const employId = row.employId || this.ids
+      getStoreStaff(employId).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改店铺员工";
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const employIds = row.employId || this.ids;
+      this.$modal.confirm('是否确认删除店铺员工编号为"' + employIds + '"的数据项?').then(function() {
+        return delStoreStaff(employIds);
+      }).then(() => {
+        this.getList();
+        this.$modal.msgSuccess("删除成功");
+      }).catch(() => {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      this.download('ss/storeStaff/export', {
+        ...this.queryParams
+      }, `storeStaff_${new Date().getTime()}.xlsx`)
+    }
+  }
+};
+</script>
diff --git a/src/views/system/device/detail.vue b/src/views/system/device/detail.vue
index b4cadfc..6e404b1 100644
--- a/src/views/system/device/detail.vue
+++ b/src/views/system/device/detail.vue
@@ -55,6 +55,43 @@
               </el-descriptions>
           </el-card>
 
+          <el-card class="box-card">
+            <el-descriptions title="归属信息" :column="4">
+              <template #extra>
+                <el-row type="flex">
+                  <el-button size="small" plain icon="el-icon-link" type="danger" @click="handleUnbindAgent" v-if="deviceData.agentId != null">解绑代理商</el-button>
+                  <bind-agent-button v-else :device-id="deviceData.deviceId" @success="getDevice" style="margin-right: 0.5em"/>
+                  <el-button size="small" plain icon="el-icon-link" type="danger" @click="handleUnbind" v-if="deviceData.userId != null">解绑商户</el-button>
+                  <bind-mch-button v-else :device-id="deviceData.deviceId" @success="getDevice" style="margin-left: 0.5em"/>
+                </el-row>
+              </template>
+              <el-descriptions-item label="设备名称">{{deviceData.deviceName | defaultValue}}</el-descriptions-item>
+              <el-descriptions-item label="服务模式">
+                <dict-tag :options="dict.type.device_service_mode" :value="deviceData.serviceMode" size="small"/>
+              </el-descriptions-item>
+              <el-descriptions-item label="所属代理" v-if="deviceData.serviceMode === DeviceServiceMode.AGENT">
+                <user-link :name="deviceData.agentName" :id="deviceData.agentId"/>
+              </el-descriptions-item>
+              <el-descriptions-item label="所属商户">
+                <user-link :name="deviceData.userName" :id="deviceData.userId"/>
+              </el-descriptions-item>
+              <el-descriptions-item label="店铺名称">
+                <store-link :name="deviceData.storeName" :id="deviceData.storeId"/>
+              </el-descriptions-item>
+              <el-descriptions-item label="月费">
+                {{deviceData.monthFee | money | defaultValue}} 元 / 月
+                (到期时间:{{deviceData.rentTime | defaultValue}})
+              </el-descriptions-item>
+              <el-descriptions-item label="平台服务费" v-if="deviceData.serviceMode === DeviceServiceMode.DIRECT">
+                {{deviceData.realServiceRate | money | defaultValue}} %
+              </el-descriptions-item>
+              <el-descriptions-item label="代理服务费"  v-if="deviceData.serviceMode === DeviceServiceMode.AGENT">
+                {{deviceData.agentServiceRate | money | defaultValue}} %
+              </el-descriptions-item>
+              <el-descriptions-item label="备注">{{deviceData.remark | defaultValue}}</el-descriptions-item>
+            </el-descriptions>
+          </el-card>
+
           <el-card class="box-card">
             <el-descriptions :column="4" title="物联网信息">
               <el-descriptions-item label="在线状态">
@@ -85,40 +122,16 @@
           </el-card>
         </el-col>
         <el-col :lg="6" :xs="24">
-          <el-card class="box-card">
-            <el-descriptions title="归属信息" :column="1">
-              <el-descriptions-item label="设备名称">{{deviceData.deviceName | defaultValue}}</el-descriptions-item>
-              <el-descriptions-item label="服务模式">
-                <dict-tag :options="dict.type.device_service_mode" :value="deviceData.serviceMode" size="small"/>
-              </el-descriptions-item>
-              <el-descriptions-item label="所属代理" v-if="deviceData.serviceMode === DeviceServiceMode.AGENT">
-                <user-link :name="deviceData.agentName" :id="deviceData.agentId"/>
-              </el-descriptions-item>
-              <el-descriptions-item label="所属商户">
-                <user-link :name="deviceData.userName" :id="deviceData.userId"/>
-              </el-descriptions-item>
-              <el-descriptions-item label="店铺名称">
-                <store-link :name="deviceData.storeName" :id="deviceData.storeId"/>
-              </el-descriptions-item>
-              <el-descriptions-item label="月费">
-                {{deviceData.monthFee | money | defaultValue}} 元 / 月
-                (到期时间:{{deviceData.rentTime | defaultValue}})
-              </el-descriptions-item>
-              <el-descriptions-item label="平台服务费" v-if="deviceData.serviceMode === DeviceServiceMode.DIRECT">
-                {{deviceData.realServiceRate | money | defaultValue}} %
-              </el-descriptions-item>
-              <el-descriptions-item label="代理服务费"  v-if="deviceData.serviceMode === DeviceServiceMode.AGENT">
-                {{deviceData.realServiceRate | money | defaultValue}} %
-              </el-descriptions-item>
-              <el-descriptions-item label="备注">{{deviceData.remark | defaultValue}}</el-descriptions-item>
-            </el-descriptions>
-
-            <el-row type="flex">
-              <el-button size="small" style="flex:1" plain icon="el-icon-link" type="danger" @click="handleUnbindAgent" v-if="deviceData.agentId != null">解绑代理商</el-button>
-              <bind-agent-button v-else style="flex: 1" :device-id="deviceData.deviceId" @success="getDevice"/>
-              <el-button size="small" style="flex:1" plain icon="el-icon-link" type="danger" @click="handleUnbind" v-if="deviceData.userId != null">解绑商户</el-button>
-              <bind-mch-button v-else style="flex: 1" :device-id="deviceData.deviceId" @success="getDevice"/>
-            </el-row>
+          <el-card class="box-card" header="分成信息">
+            <line-field v-for="bonus of deviceData.bonusList" :label="bonus.arrivalName">
+              <template #label>
+                <el-row type="flex">
+                  <dict-tag :options="dict.type.bonus_arrival_type" :value="bonus.arrivalType" size="mini"/>
+                  {{bonus.arrivalName}}
+                </el-row>
+              </template>
+              <template>{{bonus.point | money | defaultValue }} %</template>
+            </line-field>
           </el-card>
         </el-col>
       </el-row>
@@ -150,7 +163,7 @@
         </el-tabs>
       </el-card>
     </div>
-    <el-empty v-else description="设备已被删除或不存在"/>
+    <el-empty v-else description="设备不存在或已被删除"/>
 
     <!--添加时长-->
     <el-dialog title="增加时长" :visible.sync="showAddElectricity" center width="400px">
@@ -203,16 +216,18 @@ import UserLink from '@/components/Business/SmUser/UserLink.vue'
 import { $serviceType, $view } from '@/utils/mixins'
 import Recharge from '@/views/system/recharge/index.vue'
 import BooleanTag from '@/components/BooleanTag/index.vue'
-import { DeviceServiceMode, ModelTag } from '@/utils/constants'
+import { DeviceOnlineStatus, DeviceServiceMode, ModelTag } from '@/utils/constants'
 import { isEmpty } from '@/utils'
 import BindMchButton from '@/views/system/device/components/BindMchButton.vue'
 import BindAgentButton from '@/views/system/device/components/BindAgentButton.vue'
+import LineField from '@/components/LineField/index.vue'
 
 export default {
   name: 'Device/:deviceId',
   mixins: [$serviceType, $view],
-  dicts: ['sm_device_status', 'sm_device_outage_way', 'sm_device_notice_way', 'sm_model_tag', 'sm_device_online_status', 'service_type', 'device_service_mode', 'time_unit'],
+  dicts: ['sm_device_status', 'sm_device_outage_way', 'sm_device_notice_way', 'sm_model_tag', 'sm_device_online_status', 'service_type', 'device_service_mode', 'time_unit', 'bonus_arrival_type'],
   components: {
+    LineField,
     BindAgentButton,
     BindMchButton,
     BooleanTag,
@@ -228,6 +243,7 @@ export default {
       loading: false,
       deviceData: {
         modelTags: [],
+        bonusList: []
       },
       timer: null,
       surplusTime: 0, // 剩余时长
@@ -246,6 +262,9 @@ export default {
     }
   },
   computed: {
+    DeviceOnlineStatus() {
+      return DeviceOnlineStatus
+    },
     ModelTag() {
       return ModelTag
     },
@@ -451,4 +470,10 @@ export default {
   color: #ccc;
   margin-left: 1em;
 }
+.statistic {
+  margin-bottom: 1em;
+  .el-tag {
+    line-height: 26px !important;
+  }
+}
 </style>
diff --git a/src/views/system/smUser/detail.vue b/src/views/system/smUser/detail.vue
index 3efca70..1cad2e5 100644
--- a/src/views/system/smUser/detail.vue
+++ b/src/views/system/smUser/detail.vue
@@ -96,9 +96,12 @@
 
       <el-card class="box-card">
         <el-tabs>
-          <el-tab-pane label="设备列表" lazy>
+          <el-tab-pane label="商户设备列表" lazy>
             <device v-if="detail.userId != null" :query="{userId: detail.userId}" :view="views.user"/>
           </el-tab-pane>
+          <el-tab-pane label="代理设备列表" lazy>
+            <device v-if="detail.userId != null" :query="{agentId: detail.userId}" :view="views.user"/>
+          </el-tab-pane>
           <el-tab-pane label="店铺列表" lazy>
             <store :query="{userId: detail.userId}" :view="views.user"/>
           </el-tab-pane>