From be3ec4c1f11a5e090408fcd6f650557651fcf007 Mon Sep 17 00:00:00 2001
From: MrShi <1878285526@qq.com>
Date: 星期一, 13 四月 2026 20:17:16 +0800
Subject: [PATCH] 页面

---
 admin/src/views/business/memberManage.vue                      |  149 ++
 admin/src/components/business/OperaShopApprovalWindow.vue      |  450 +++++++
 admin/src/api/business/shopWithdraw.js                         |   29 
 admin/src/views/business/storeList.vue                         |    5 
 admin/src/components/business/OperaShopEditWindow.vue          |   19 
 admin/src/components/business/OperaShopInfoSeeWindow.vue       |  416 +++++++
 admin/src/views/business/driverList.vue                        |  167 ++
 admin/src/views/business/shopWithdrawList.vue                  |  156 ++
 admin/src/components/business/OperaWithdrawDetailWindow.vue    |  297 +++++
 admin/src/views/business/vehicleType.vue                       |   99 +
 admin/src/components/business/OperaGoodsCategoryEditWindow.vue |  204 +++
 admin/src/views/business/itemLevel.vue                         |   96 +
 admin/src/api/business/goodsCategory.js                        |   33 
 admin/src/components/business/OperaMemberDetail.vue            |  185 +++
 admin/src/components/business/OperaShopInfoWindow.vue          |  100 +
 admin/src/views/business/shopQualificationList.vue             |  155 ++
 admin/src/api/business/shopInfo.js                             |    5 
 admin/src/api/business/banner.js                               |   43 
 admin/src/views/business/baggageType.vue                       |   96 +
 admin/src/views/business/sysParams.vue                         |  162 ++
 admin/src/api/business/revenue.js                              |   39 
 admin/src/components/business/OperaBannerEditWindow.vue        |  135 ++
 admin/src/views/business/memberList.vue                        |  105 +
 admin/src/views/business/bannerList.vue                        |  138 ++
 admin/src/views/business/goodsCategoryList.vue                 |   96 +
 admin/src/api/business/sysParams.js                            |   11 
 admin/src/api/business/memberManage.js                         |   18 
 admin/src/api/business/driver.js                               |   24 
 28 files changed, 3,385 insertions(+), 47 deletions(-)

diff --git a/admin/src/api/business/banner.js b/admin/src/api/business/banner.js
new file mode 100644
index 0000000..84e4f4d
--- /dev/null
+++ b/admin/src/api/business/banner.js
@@ -0,0 +1,43 @@
+import request from '../../utils/request'
+
+export function fetchList (data) {
+  return request.post('/business/banner/page', data, {
+    trim: true
+  })
+}
+
+export function create (data) {
+  return request.post('/business/banner/create', data)
+}
+
+export function updateStatus (data) {
+  return request.post('/business/banner/updateStatus', data)
+}
+
+export function updateById (data) {
+  return request.post('/business/banner/updateById', data)
+}
+
+export function getById (id) {
+  return request.get(`/business/banner/${id}`)
+}
+
+export function deleteById (id) {
+  return request.get(`/business/banner/delete/${id}`)  
+}
+
+export function deleteByIdInBatch (ids) {
+  return request.get('/business/banner/delete/batch', {
+    params: {
+      ids
+    }
+  })
+}
+
+// 瀵煎嚭Excel
+export function exportExcel (data) {
+  return request.post('/business/banner/exportExcel', data, {
+    download: true,
+    trim: true
+  })
+}
\ No newline at end of file
diff --git a/admin/src/api/business/driver.js b/admin/src/api/business/driver.js
new file mode 100644
index 0000000..a1a4c44
--- /dev/null
+++ b/admin/src/api/business/driver.js
@@ -0,0 +1,24 @@
+import request from '../../utils/request'
+
+export function fetchList (data) {
+  return request.post('/business/driver/page', data, {
+    trim: true
+  })
+}
+
+export function getById (id) {
+  return request.get(`/business/driver/${id}`)
+}
+
+export function updateStatus (data) {
+  return request.post('/business/driver/updateStatus', data, {
+    trim: true
+  })
+}
+
+export function exportExcel (data) {
+  return request.post('/business/driver/exportExcel', data, {
+    download: true,
+    trim: true
+  })
+}
diff --git a/admin/src/api/business/goodsCategory.js b/admin/src/api/business/goodsCategory.js
new file mode 100644
index 0000000..4d1bfec
--- /dev/null
+++ b/admin/src/api/business/goodsCategory.js
@@ -0,0 +1,33 @@
+import request from '../../utils/request'
+
+export function fetchList (data) {
+  return request.post('/business/category/page', data, {
+    trim: true
+  })
+}
+
+export function create (data) {
+  return request.post('/business/category/create', data, {
+    trim: true
+  })
+}
+
+export function updateStatus (data) {
+  return request.post('/business/category/updateStatus', data, {
+    trim: true
+  })
+}
+
+export function updateById (data) {
+  return request.post('/business/category/updateById', data, {
+    trim: true
+  })
+}
+
+export function getById (id) {
+  return request.get(`/business/category/${id}`)
+}
+
+export function deleteById (id) {
+  return request.get(`/business/category/delete/${id}`)
+}
diff --git a/admin/src/api/business/memberManage.js b/admin/src/api/business/memberManage.js
new file mode 100644
index 0000000..797020e
--- /dev/null
+++ b/admin/src/api/business/memberManage.js
@@ -0,0 +1,18 @@
+import request from '../../utils/request'
+
+export function fetchList (data) {
+  return request.post('/business/member/list/page', data, {
+    trim: true
+  })
+}
+
+export function getById (id) {
+  return request.get(`/business/member/detail/${id}`)
+}
+
+export function exportExcel (data) {
+  return request.post('/business/member/list/exportExcel', data, {
+    download: true,
+    trim: true
+  })
+}
diff --git a/admin/src/api/business/revenue.js b/admin/src/api/business/revenue.js
new file mode 100644
index 0000000..335f68a
--- /dev/null
+++ b/admin/src/api/business/revenue.js
@@ -0,0 +1,39 @@
+import request from '../../utils/request'
+
+export function fetchList (data) {
+  return request.post('/business/revenue/page', data, {
+    trim: true
+  })
+}
+
+export function create (data) {
+  return request.post('/business/revenue/create', data)
+}
+
+export function updateStatus (data) {
+  return request.post('/business/revenue/updateStatus', data)
+}
+
+export function updateById (data) {
+  return request.post('/business/revenue/updateShop', data)
+}
+
+export function deleteById (id) {
+  return request.get(`/business/revenue/delete/${id}`)  
+}
+
+export function deleteByIdInBatch (ids) {
+  return request.get('/business/revenue/delete/batch', {
+    params: {
+      ids
+    }
+  })
+}
+
+// 瀵煎嚭Excel
+export function exportExcel (data) {
+  return request.post('/business/revenue/exportExcel', data, {
+    download: true,
+    trim: true
+  })
+}
\ No newline at end of file
diff --git a/admin/src/api/business/shopInfo.js b/admin/src/api/business/shopInfo.js
index d394d7f..3ec1001 100644
--- a/admin/src/api/business/shopInfo.js
+++ b/admin/src/api/business/shopInfo.js
@@ -44,3 +44,8 @@
 export function resetPassword (data) {
   return request.post('/business/shopInfo/resetPassword', data)
 }
+
+// 闂ㄥ簵瀹℃壒
+export function audit (data) {
+  return request.post('/business/shopInfo/audit', data)
+}
diff --git a/admin/src/api/business/shopWithdraw.js b/admin/src/api/business/shopWithdraw.js
new file mode 100644
index 0000000..4bec4a8
--- /dev/null
+++ b/admin/src/api/business/shopWithdraw.js
@@ -0,0 +1,29 @@
+import request from '../../utils/request'
+
+export function fetchList (data) {
+  return request.post('/business/withdrawalOrders/page', data, {
+    trim: true
+  })
+}
+
+export function getById (id) {
+  return request.get(`/business/withdrawalOrders/${id}`)
+}
+
+export function getTotalAmount (data) {
+  return request.post('/business/withdrawalOrders/totalAmount', data, {
+    trim: true
+  })
+}
+
+export function audit (data) {
+  return request.post('/business/withdrawalOrders/audit', data, {
+    trim: true
+  })
+}
+
+export function approve (data) {
+  return request.post('/business/withdrawalOrders/approve', data, {
+    trim: true
+  })
+}
diff --git a/admin/src/api/business/sysParams.js b/admin/src/api/business/sysParams.js
new file mode 100644
index 0000000..0ca888f
--- /dev/null
+++ b/admin/src/api/business/sysParams.js
@@ -0,0 +1,11 @@
+import request from '../../utils/request'
+
+export function getParams () {
+  return request.get('/business/operationConfig')
+}
+
+export function saveParams (data) {
+  return request.post('/business/operationConfig/save', data, {
+    trim: true
+  })
+}
diff --git a/admin/src/components/business/OperaBannerEditWindow.vue b/admin/src/components/business/OperaBannerEditWindow.vue
new file mode 100644
index 0000000..d688d0d
--- /dev/null
+++ b/admin/src/components/business/OperaBannerEditWindow.vue
@@ -0,0 +1,135 @@
+<template>
+  <GlobalWindow
+    :title="title"
+    :visible.sync="visible"
+    width="500px"
+    :confirm-working="isWorking"
+    @confirm="confirm"
+  >
+    <el-form ref="form" :model="form" :rules="rules">
+      <el-form-item label="鏍囬" prop="title">
+        <el-input v-model="form.title" placeholder="璇疯緭鍏ユ爣棰�"></el-input>
+      </el-form-item>
+      <el-form-item label="鍥剧墖" prop="imgurl">
+        <UploadImages
+          :fileList="imgurl ? [{ url: imgurl }] : []"
+          :uploadData="{ folder: 'banner' }"
+          :maxCount="1"
+          @getFileList="e => { form.imgurl = e.fileurl; imgurl = e.url }"
+          @deleteRow="form.imgurl = ''; imgurl = ''" />
+      </el-form-item>
+      <el-form-item label="鎺掑簭鐮�" prop="sortnum">
+        <el-input v-model="form.sortnum" placeholder="璇疯緭鍏ユ帓搴忕爜"></el-input>
+      </el-form-item>
+      <el-form-item label="鐘舵��" prop="status">
+        <el-switch
+          v-model="form.status"
+          active-color="#13ce66"
+          inactive-color="#ff4949"
+          :active-value="1"
+          :inactive-value="0"
+        ></el-switch>
+      </el-form-item>
+      <el-form-item label="灞曠ず浣嶇疆" prop="position">
+        <el-select v-model="form.position" placeholder="璇烽�夋嫨灞曠ず浣嶇疆">
+          <el-option label="浼氬憳绔椤佃疆鎾�" :value="0"></el-option>
+          <el-option label="鍙告満APP寮曞椤�" :value="1"></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="璺宠浆鏂瑰紡" prop="type">
+        <el-select v-model="form.type" placeholder="璇烽�夋嫨璺宠浆鏂瑰紡">
+          <el-option label="鏃�" :value="0"></el-option>
+          <el-option label="瀵屾枃鏈�" :value="1"></el-option>
+          <el-option label="澶栭摼" :value="2"></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="鍐呭" prop="content" v-if="form.type === 1">
+        <RichEditor :richData="form.content" :styleEditor="styleEditor" @getWangedditor="getWangedditor" :readonly="false"/>
+      </el-form-item>
+      <el-form-item label="鍐呭" prop="content" v-if="form.type === 2">
+        <el-input v-model="form.content" placeholder="璇疯緭鍏ュ唴瀹�"></el-input>
+      </el-form-item>
+    </el-form>
+  </GlobalWindow>
+</template>
+
+<script>
+import BaseOpera from '@/components/base/BaseOpera'
+import GlobalWindow from '@/components/common/GlobalWindow'
+import UploadImages from '@/components/common/uploadImages'
+import { getById } from '@/api/business/banner'
+import RichEditor from '@/components/common/RichEditor'
+export default {
+  name: 'OperaBannerEditWindow',
+  extends: BaseOpera,
+  components: { GlobalWindow, UploadImages, RichEditor },
+  data () {
+    return {
+      // 琛ㄥ崟鏁版嵁
+      styleEditor:'border: 1px solid #ccc;display: inline-block;',
+      form: {
+        id: null,
+        title: '',
+        content: '',
+        position: '',
+        imgurl: '',
+        type: '',
+        sortnum: '',
+        status: 1
+      },
+      imgurl: '',
+      rules: {
+        position: [{ required: true, message: '璇烽�夋嫨灞曠ず浣嶇疆', trigger: 'change' }],
+        imgurl: [{ required: true, message: '璇蜂笂浼犲浘鐗�', trigger: 'change' }],
+        type: [{ required: true, message: '璇烽�夋嫨璺宠浆鏂瑰紡', trigger: 'change' }],
+        content: [{ required: true, message: '璇疯緭鍏ュ唴瀹�', trigger: 'blur' }]
+      }
+    }
+  },
+  created () {
+    this.config({
+      api: '/business/banner',
+      'field.id': 'id'
+    })
+  },
+  methods: {
+    open (title, row) {
+      this.title = title
+      if (row && row.id) {
+        getById(row.id).then(res => {
+          this.form = {
+            id: res.id,
+            title: res.title || '',
+            position: res.position,
+            imgurl: res.imgurl || '',
+            type: res.type,
+            sortnum: res.sortnum,
+            status: res.status ?? 1,
+            content: res.content || ''
+          }
+          this.imgurl = res.imgurlFull
+          this.visible = true
+        }).catch(e => {
+          this.$tip.apiFailed(e)
+        })
+      } else {
+        this.form = {
+          id: null,
+          title: '',
+          position: '',
+          imgurl: '',
+          type: '',
+          sortnum: '',
+          status: 1,
+          content: ''
+        }
+        this.imgurl = ''
+        this.visible = true
+      }
+    },
+    getWangedditor (data) {
+      this.form.content = data
+    }
+  }
+}
+</script>
diff --git a/admin/src/components/business/OperaGoodsCategoryEditWindow.vue b/admin/src/components/business/OperaGoodsCategoryEditWindow.vue
new file mode 100644
index 0000000..6736820
--- /dev/null
+++ b/admin/src/components/business/OperaGoodsCategoryEditWindow.vue
@@ -0,0 +1,204 @@
+<template>
+  <GlobalWindow
+    :title="title"
+    :visible.sync="visible"
+    width="500px"
+    :confirm-working="isWorking"
+    @confirm="confirm"
+  >
+    <el-form ref="form" :model="form" :rules="rules">
+      <el-form-item label="绫诲瀷鍚嶇О" prop="name" v-if="form.type === 1">
+        <el-input v-model="form.name" placeholder="璇疯緭鍏ョ被鍨嬪悕绉�"></el-input>
+      </el-form-item>
+      <el-form-item label="琛屾潕绫诲瀷" prop="name" v-if="form.type === 4">
+        <el-input v-model="form.name" placeholder="璇疯緭鍏ヨ鏉庣被鍨�"></el-input>
+      </el-form-item>
+      <el-form-item label="鐗╁搧鍚嶇О" prop="name" v-if="form.type === 2">
+        <el-input v-model="form.name" placeholder="璇疯緭鍏ョ墿鍝佸悕绉�"></el-input>
+      </el-form-item>
+      <el-form-item label="绛夌骇鍚嶇О" prop="name" v-if="form.type === 3">
+        <el-input v-model="form.name" placeholder="璇疯緭鍏ョ瓑绾у悕绉�"></el-input>
+      </el-form-item>
+      <el-form-item label="閫氳鏂瑰紡" prop="detail" v-if="form.type === 1">
+        <el-select v-model="form.detail" placeholder="璇烽�夋嫨閫氳鏂瑰紡">
+          <el-option label="鏈哄姩杞�" value="driving"></el-option>
+          <el-option label="闈炴満鍔ㄨ溅" value="bicycling"></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="涓婁紶椹鹃┒璇�" prop="otherField" v-if="form.type === 1">
+        <el-radio-group v-model="form.otherField">
+          <el-radio label="1">闇�瑕�</el-radio>
+          <el-radio label="0">涓嶉渶瑕�</el-radio>
+        </el-radio-group>
+      </el-form-item>
+      <el-form-item label="鏄惁鐗瑰ぇ灏哄" prop="detail" v-if="form.type === 4">
+        <el-radio-group v-model="form.detail">
+          <el-radio label="0">鍚�</el-radio>
+          <el-radio label="1">鏄�</el-radio>
+        </el-radio-group>
+      </el-form-item>
+      <el-form-item label="鍥炬爣" prop="iconFull" v-if="form.type === 4">
+        <UploadImages
+          :fileList="form.iconFull ? [{ url: form.iconFull }] : []"
+          :uploadData="{ folder: 'category' }"
+          :maxCount="1"
+          @getFileList="e => { form.icon = e.fileurl; form.iconFull = e.url }"
+          @deleteRow="form.icon = ''; form.iconFull = ''" />
+      </el-form-item>
+      <el-form-item label="鐗╁搧绛夌骇" prop="relationId" v-if="form.type === 2">
+        <el-select v-model="form.relationId" placeholder="璇烽�夋嫨鐗╁搧绛夌骇">
+          <el-option
+            v-for="item in list"
+            :key="item.id"
+            :label="item.name"
+            :value="item.id" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="鎵�闇�鍙告満璇勭骇" prop="detail" v-if="form.type === 3">
+        <el-select v-model="form.detail" placeholder="璇烽�夋嫨鍙告満璇勭骇">
+          <el-option label="S" :value="5"></el-option>
+          <el-option label="A" :value="4"></el-option>
+          <el-option label="B" :value="3"></el-option>
+          <el-option label="C" :value="2"></el-option>
+          <el-option label="D" :value="1"></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="瀵勫瓨璇存槑" prop="detail" v-if="form.type === 2">
+        <el-input v-model="form.detail" type="textarea" :rows="3" placeholder="璇疯緭鍏ュ瘎瀛樿鏄�"></el-input>
+      </el-form-item>
+      <el-form-item label="澶囨敞璇存槑" prop="remark" v-if="form.type === 3 || form.type === 4">
+        <el-input v-model="form.remark" type="textarea" :rows="3" placeholder="璇疯緭鍏ュ娉ㄨ鏄�"></el-input>
+      </el-form-item>
+      <el-form-item label="鎺掑簭" prop="sortnum">
+        <el-input v-model="form.sortnum" placeholder="璇疯緭鍏ユ帓搴�"></el-input>
+      </el-form-item>
+      <el-form-item label="鐘舵��" prop="status">
+        <div style="display: flex; align-items: center;">
+          <el-switch
+            v-model="form.status"
+            active-color="#13ce66"
+            inactive-color="#ff4949"
+            :active-value="0"
+            :inactive-value="1"
+          ></el-switch>
+          <span v-if="form.type === 2" style="margin-left: 5px; font-size: 12px; color: #909399;">寮�鍚悗锛岃鍩庡競涓嬮棬搴楀彲琚細鍛樻煡鐪�</span>
+        </div>
+      </el-form-item>
+    </el-form>
+  </GlobalWindow>
+</template>
+
+<script>
+import BaseOpera from '@/components/base/BaseOpera'
+import GlobalWindow from '@/components/common/GlobalWindow'
+import { getById, fetchList } from '@/api/business/goodsCategory'
+import UploadImages from '@/components/common/uploadImages'
+export default {
+  name: 'OperaGoodsCategoryEditWindow',
+  extends: BaseOpera,
+  components: { GlobalWindow, UploadImages },
+  data () {
+    return {
+      form: {
+        id: null,
+        name: '',
+        relationId: '',
+        detail: '',
+        sortnum: '',
+        status: 0,
+        type: '',
+        remark: '',
+        icon: '',
+        iconFull: '',
+        otherField: '1'
+      },
+      rules: {},
+      list: []
+    }
+  },
+  created () {
+    this.config({
+      api: '/business/goodsCategory',
+      'field.id': 'id'
+    })
+  },
+  methods: {
+    open (title, row, type) {
+      this.title = title
+      if (type === 2) {
+        fetchList({
+          capacity: 99999,
+          page: 1,
+          model: {
+            type: 3
+          }
+        }).then(res => {
+          this.list = res.records || []
+        })
+      }
+      if (row && row.id) {
+        getById(row.id).then(res => {
+          this.form = {
+            id: res.id,
+            name: res.name || '',
+            relationId: res.relationId || '',
+            detail: res.detail || '',
+            sortnum: res.sortnum || '',
+            status: res.status ?? 0,
+            type: res.type ?? 2,
+            remark: res.remark || '',
+            icon: res.icon || '',
+            iconFull: res.iconFull || '',
+            otherField: res.otherField || ''
+          }
+          this.visible = true
+        }).catch(e => {
+          this.$tip.apiFailed(e)
+        })
+      } else {
+        this.form = {
+          id: null,
+          name: '',
+          relationId: '',
+          detail: '',
+          sortnum: '',
+          status: 0,
+          type: '',
+          remark: '',
+          icon: '',
+          iconFull: '',
+          otherField: '1'
+        }
+        if (type === 4) {
+          this.form.detail = '0'
+        }
+        this.form.type = type
+        this.visible = true
+      }
+      if (this.form.type === 2) {
+        this.rules = {
+          name: [{ required: true, message: '璇疯緭鍏ョ墿鍝佸悕绉�', trigger: 'blur' }],
+          relationId: [{ required: true, message: '璇烽�夋嫨鐗╁搧绛夌骇', trigger: 'blur' }]
+        }
+      } else if (this.form.type === 3) {
+        this.rules = {
+          name: [{ required: true, message: '璇疯緭鍏ョ瓑绾у悕绉�', trigger: 'blur' }],
+          detail: [{ required: true, message: '璇烽�夋嫨鍙告満璇勭骇', trigger: 'blur' }]
+        }
+      } else if (this.form.type === 4) {
+        this.rules = {
+          name: [{ required: true, message: '璇疯緭鍏ヨ鏉庣被鍨�', trigger: 'blur' }],
+          detail: [{ required: true, message: '璇烽�夋嫨鏄惁鐗瑰ぇ灏哄', trigger: 'blur' }],
+          icon: [{ required: true, message: '璇蜂笂浼犲浘鏍�', trigger: 'blur' }]
+        }
+      } else if (this.form.type === 1) {
+        this.rules = {
+          name: [{ required: true, message: '璇疯緭鍏ョ被鍨嬪悕绉�', trigger: 'blur' }],
+          detail: [{ required: true, message: '璇烽�夋嫨閫氳鏂瑰紡', trigger: 'blur' }],
+          otherField: [{ required: true, message: '璇烽�夋嫨閫氳鏂瑰紡', trigger: 'blur' }]
+        }
+      }
+    }
+  }
+}
+</script>
diff --git a/admin/src/components/business/OperaMemberDetail.vue b/admin/src/components/business/OperaMemberDetail.vue
new file mode 100644
index 0000000..6ad3abb
--- /dev/null
+++ b/admin/src/components/business/OperaMemberDetail.vue
@@ -0,0 +1,185 @@
+<template>
+  <GlobalWindow
+    :title="title"
+    :visible.sync="visible"
+    width="600px"
+    :withFooter="false"
+  >
+    <div class="detail-container">
+      <div class="section">
+        <div class="section-header">
+          <span class="section-title">鐢ㄦ埛淇℃伅</span>
+          <span class="status-tag">
+            <el-tag type="success" v-if="detailInfo.telephone">宸叉巿鏉冩墜鏈哄彿</el-tag>
+            <el-tag type="warning" v-else>鏈巿鏉冩墜鏈哄彿</el-tag>
+          </span>
+        </div>
+        <div class="info-grid">
+          <div class="info-item">
+            <span class="label">寰俊openid锛�</span>
+            <span class="value">{{ detailInfo.openId }}</span>
+          </div>
+          <div class="info-item">
+            <span class="label">鐢ㄦ埛鏄电О锛�</span>
+            <span class="value">{{ detailInfo.nickName }}</span>
+          </div>
+          <div class="info-item">
+            <span class="label">浼氬憳濮撳悕锛�</span>
+            <span class="value">{{ detailInfo.name }}</span>
+          </div>
+          <div class="info-item">
+            <span class="label">鎺堟潈鎵嬫満鍙凤細</span>
+            <span class="value">{{ detailInfo.telephone }}</span>
+          </div>
+          <div class="info-item">
+            <span class="label">鐘舵�侊細</span>
+            <span class="value">{{ detailInfo.status === 0 ? '姝e父' : detailInfo.status === 1 ? '鍋滅敤' : '宸叉敞閿�' }}</span>
+          </div>
+        </div>
+      </div>
+    </div>
+  </GlobalWindow>
+</template>
+
+<script>
+import GlobalWindow from '@/components/common/GlobalWindow'
+import { getById } from '@/api/business/memberManage'
+import BaseOpera from '@/components/base/BaseOpera'
+export default {
+  name: 'OperaMemberDetail',
+  extends: BaseOpera,
+  components: { GlobalWindow, BaseOpera },
+  data () {
+    return {
+      detailInfo: {
+        id: null,
+        openId: '',
+        nickName: '',
+        name: '',
+        phone: '',
+        status: 1
+      }
+    }
+  },
+  methods: {
+    open (title, row) {
+      this.title = title
+      getById(row.id).then(res => {
+        this.detailInfo = {
+          id: res.id,
+          openId: res.openId,
+          nickName: res.nickName,
+          name: res.name,
+          phone: res.phone,
+          status: res.status
+        }
+        this.visible = true
+      }).catch(e => {
+        this.$tip.apiFailed(e)
+      })
+    }
+  }
+}
+</script>
+
+<style scoped>
+.detail-container {
+  padding: 20px;
+}
+.section {
+  margin-bottom: 30px;
+}
+.section-header {
+  display: flex;
+  align-items: center;
+  gap: 15px;
+  margin-bottom: 15px;
+}
+.section-title {
+  font-size: 16px;
+  font-weight: bold;
+  color: #303133;
+  padding-left: 10px;
+  border-left: 4px solid #2E68EC;
+}
+.status-tag {
+  padding: 4px 12px;
+  border-radius: 4px;
+  font-size: 12px;
+}
+.status-pending {
+  background: #fdf6ec;
+  color: #E6A23C;
+}
+.status-success {
+  background: #f0f9eb;
+  color: #67C23A;
+}
+.status-reject {
+  background: #fef0f0;
+  color: #F56C6C;
+}
+.info-grid {
+  display: grid;
+  grid-template-columns: repeat(2, 1fr);
+  gap: 15px;
+  padding: 0 10px;
+}
+.info-item {
+  display: flex;
+  font-size: 14px;
+}
+.info-item .label {
+  color: #909399;
+  min-width: 90px;
+}
+.info-item .value {
+  color: #606266;
+}
+.info-item .amount {
+  color: #f56c6c;
+  font-weight: bold;
+}
+.info-item.full-width {
+  grid-column: span 2;
+}
+.timeline-content {
+  padding: 10px;
+  background: #f5f7fa;
+  border-radius: 4px;
+}
+.timeline-title {
+  font-size: 14px;
+  font-weight: bold;
+  color: #303133;
+  margin-bottom: 8px;
+}
+.timeline-info {
+  display: flex;
+  gap: 20px;
+  font-size: 13px;
+  color: #606266;
+  margin-bottom: 5px;
+}
+.timeline-remark {
+  font-size: 13px;
+  color: #909399;
+}
+.approval-form {
+  padding: 20px;
+  background: #f5f7fa;
+  border-top: 1px solid #eee;
+}
+.approval-form /deep/ .el-form-item {
+  margin-bottom: 15px;
+}
+.approval-form /deep/ .el-form-item:last-child {
+  margin-bottom: 0;
+}
+.approval-buttons {
+  display: flex;
+  justify-content: flex-end;
+  gap: 10px;
+  margin-top: 15px;
+}
+</style>
diff --git a/admin/src/components/business/OperaShopApprovalWindow.vue b/admin/src/components/business/OperaShopApprovalWindow.vue
new file mode 100644
index 0000000..cf67cd7
--- /dev/null
+++ b/admin/src/components/business/OperaShopApprovalWindow.vue
@@ -0,0 +1,450 @@
+<template>
+  <GlobalWindow
+    :title="title"
+    :withFooter="false"
+    :visible.sync="visible"
+    width="80%"
+  >
+    <div class="store-header" v-if="storeInfo">
+      <div class="store-header-left">
+        <el-image :src="storeInfo.payMemberCoverImage ? storeInfo.imgPrefix + storeInfo.payMemberCoverImage : ''" fit="cover" class="store-avatar">
+          <div slot="error" class="image-slot">
+            <i class="el-icon-picture-outline"></i>
+          </div>
+        </el-image>
+      </div>
+      <div class="store-header-right">
+        <div class="store-name">{{ storeInfo.name }}</div>
+        <div class="store-info-row">
+          <span class="info-item">
+            <span class="label">闂ㄥ簵绫诲瀷锛�</span>
+            <span class="value">{{ storeInfo.companyType === 1 ? '浼佷笟' : '涓汉' }}</span>
+          </span>
+          <span class="info-item">
+            <span class="label">鑱旂郴浜猴細</span>
+            <span class="value">{{ storeInfo.linkName }}</span>
+          </span>
+          <span class="info-item">
+            <span class="label">鑱旂郴鐢佃瘽锛�</span>
+            <span class="value">{{ storeInfo.linkPhone }}</span>
+          </span>
+          <span class="info-item">
+            <span class="label">韬唤璇佸彿锛�</span>
+            <span class="value">{{ storeInfo.idcard }}</span>
+          </span>
+        </div>
+      </div>
+    </div>
+
+    <div class="qualification-content" v-if="storeInfo">
+      <div class="qualification-section">
+        <h4 class="section-title">鍩烘湰淇℃伅</h4>
+        <div class="info-grid">
+          <div class="info-row">
+            <span class="label">鎵�鍦ㄧ渷甯傚尯锛�</span>
+            <span class="value">{{ storeInfo.provinceName || '' }} {{ storeInfo.cityName || '' }} {{ storeInfo.areaName || '' }}</span>
+          </div>
+          <div class="info-row">
+            <span class="label">闂ㄥ簵鍦板潃锛�</span>
+            <span class="value">{{ storeInfo.address }}</span>
+          </div>
+          <div class="info-row">
+            <span class="label">闂ㄥ簵鐘舵�侊細</span>
+            <span class="value">{{ storeInfo.auditStatus === 0 ? '寰呭鎵�' : storeInfo.auditStatus === 1 ? '瀹℃壒閫氳繃' : '瀹℃壒鏈�氳繃' }}</span>
+          </div>
+          <div class="info-row">
+            <span class="label">閰嶉�佽寖鍥达細</span>
+            <span class="value">{{ storeInfo.deliveryRange || '鏆傛棤' }}</span>
+          </div>
+        </div>
+      </div>
+
+      <div class="qualification-section">
+        <h4 class="section-title">涓讳綋璧勮川</h4>
+        <template v-if="storeInfo.companyType === 1">
+          <div class="info-grid">
+            <div class="info-row">
+              <span class="label">娉曚汉濮撳悕锛�</span>
+              <span class="value">{{ storeInfo.legalPersonName }}</span>
+            </div>
+            <div class="info-row">
+              <span class="label">娉曚汉鎵嬫満鍙凤細</span>
+              <span class="value">{{ storeInfo.legalPersonPhone }}</span>
+            </div>
+            <div class="info-row">
+              <span class="label">娉曚汉韬唤璇佸彿鐮侊細</span>
+              <span class="value">{{ storeInfo.legalPersonCard }}</span>
+            </div>
+          </div>
+          <div class="image-section">
+            <div class="image-item">
+              <span class="label">娉曚汉韬唤璇佹闈細</span>
+              <el-image :src="storeInfo.idcardImg" fit="cover" class="qualification-image" :preview-src-list="[storeInfo.idcardImg]">
+                <div slot="error" class="image-slot"><i class="el-icon-picture-outline"></i></div>
+              </el-image>
+            </div>
+            <div class="image-item">
+              <span class="label">娉曚汉韬唤璇佸弽闈細</span>
+              <el-image :src="storeInfo.idcardImgBack" fit="cover" class="qualification-image" :preview-src-list="[storeInfo.idcardImgBack]">
+                <div slot="error" class="image-slot"><i class="el-icon-picture-outline"></i></div>
+              </el-image>
+            </div>
+            <div class="image-item">
+              <span class="label">钀ヤ笟鎵х収锛�</span>
+              <el-image :src="storeInfo.businessImg" fit="cover" class="qualification-image" :preview-src-list="[storeInfo.businessImg]">
+                <div slot="error" class="image-slot"><i class="el-icon-picture-outline"></i></div>
+              </el-image>
+            </div>
+          </div>
+        </template>
+        <template v-else>
+          <div class="image-item-row">
+            <span class="label">韬唤璇佹闈細</span>
+            <el-image :src="storeInfo.idcardImg" fit="cover" class="qualification-image" :preview-src-list="[storeInfo.idcardImg]">
+              <div slot="error" class="image-slot"><i class="el-icon-picture-outline"></i></div>
+            </el-image>
+          </div>
+          <div class="image-item-row">
+            <span class="label">韬唤璇佸弽闈細</span>
+            <el-image :src="storeInfo.idcardImgBack" fit="cover" class="qualification-image" :preview-src-list="[storeInfo.idcardImgBack]">
+              <div slot="error" class="image-slot"><i class="el-icon-picture-outline"></i></div>
+            </el-image>
+          </div>
+          <div class="image-item-row">
+            <span class="label">鏈夋晥鍔冲姩鍚堝悓锛�</span>
+            <div class="image-list">
+              <el-image v-for="(img, index) in storeInfo.laborContractImgs" :key="index" :src="img" fit="cover" class="qualification-image" :preview-src-list="storeInfo.laborContractImgs">
+                <div slot="error" class="image-slot"><i class="el-icon-picture-outline"></i></div>
+              </el-image>
+            </div>
+          </div>
+          <div class="image-item-row">
+            <span class="label">绀句繚缂寸撼璇佹槑锛�</span>
+            <div class="image-list">
+              <el-image v-for="(img, index) in storeInfo.socialSecurityImgs" :key="index" :src="img" fit="cover" class="qualification-image" :preview-src-list="storeInfo.socialSecurityImgs">
+                <div slot="error" class="image-slot"><i class="el-icon-picture-outline"></i></div>
+              </el-image>
+            </div>
+          </div>
+        </template>
+      </div>
+
+      <div class="qualification-section" v-if="storeInfo.companyType === 1">
+        <h4 class="section-title">闂ㄥ簵鐓х墖鍙婂叾浠栨潗鏂�</h4>
+        <div class="image-item-row">
+          <span class="label">闂ㄥ簵闂ㄥご鐓э細</span>
+          <div class="image-list">
+            <el-image v-for="(img, index) in storeInfo.storeFrontImgs" :key="index" :src="img" fit="cover" class="qualification-image" :preview-src-list="storeInfo.storeFrontImgs">
+              <div slot="error" class="image-slot"><i class="el-icon-picture-outline"></i></div>
+            </el-image>
+          </div>
+        </div>
+        <div class="image-item-row">
+          <span class="label">闂ㄥ簵鍐呴儴鐓х墖锛�</span>
+          <div class="image-list">
+            <el-image v-for="(img, index) in storeInfo.storeInteriorImgs" :key="index" :src="img" fit="cover" class="qualification-image" :preview-src-list="storeInfo.storeInteriorImgs">
+              <div slot="error" class="image-slot"><i class="el-icon-picture-outline"></i></div>
+            </el-image>
+          </div>
+        </div>
+        <div class="image-item-row">
+          <span class="label">鍏跺畠鏉愭枡锛�</span>
+          <div class="image-list">
+            <el-image v-for="(img, index) in storeInfo.otherMaterialImgs" :key="index" :src="img" fit="cover" class="qualification-image" :preview-src-list="storeInfo.otherMaterialImgs">
+              <div slot="error" class="image-slot"><i class="el-icon-picture-outline"></i></div>
+            </el-image>
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <div class="approval-section" v-if="storeInfo && storeInfo.auditStatus !== 0">
+      <div class="approval-result" :class="storeInfo.auditStatus === 1 ? 'approval-pass' : 'approval-reject'">
+        <div class="approval-status" v-if="storeInfo.auditStatus === 1">
+          <i class="el-icon-circle-check"></i>
+          <span>瀹℃牳閫氳繃</span>
+        </div>
+        <div class="approval-status" v-else>
+          <i class="el-icon-circle-close"></i>
+          <span>瀹℃牳鎷掔粷</span>
+        </div>
+        <div class="approval-info" v-if="storeInfo.auditStatus === 1">
+          <span class="info-item">瀹℃牳鏃堕棿锛歿{ storeInfo.auditTime }}</span>
+          <span class="info-item">瀹℃牳浜猴細{{ storeInfo.auditName }}</span>
+        </div>
+        <div class="approval-info" v-else>
+          <div class="info-item" v-if="storeInfo.auditRemark">澶囨敞锛歿{ storeInfo.auditRemark }}</div>
+          <div class="info-item">瀹℃牳鏃堕棿锛歿{ storeInfo.auditTime }}</div>
+          <div class="info-item">瀹℃牳浜猴細{{ storeInfo.auditName }}</div>
+        </div>
+      </div>
+    </div>
+
+    <div class="approval-form" v-if="storeInfo && storeInfo.auditStatus === 0">
+      <el-form ref="approvalForm" :model="approvalForm" :rules="approvalRules">
+        <el-form-item label="瀹℃壒缁撴灉" prop="auditStatus">
+          <el-radio-group v-model="approvalForm.auditStatus" @change="handleAuditStatusChange">
+            <el-radio :label="0">閫氳繃</el-radio>
+            <el-radio :label="1">鎷掔粷</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="瀹℃壒鎰忚" prop="auditRemark">
+          <el-input
+            v-model="approvalForm.auditRemark"
+            type="textarea"
+            :rows="2"
+            :placeholder="approvalForm.auditStatus === 2 ? '璇疯緭鍏ユ嫆缁濆師鍥狅紙蹇呭~锛�' : '璇疯緭鍏ュ鎵规剰瑙�'"
+            style="width: 300px"
+          ></el-input>
+        </el-form-item>
+        <section class="approval-buttons">
+          <el-button type="primary" @click="handleSubmit" :loading="isWorking.submit">鎻愪氦</el-button>
+          <el-button @click="handleCancel">鍙栨秷</el-button>
+        </section>
+      </el-form>
+    </div>
+  </GlobalWindow>
+</template>
+
+<script>
+import BaseOpera from '@/components/base/BaseOpera'
+import GlobalWindow from '@/components/common/GlobalWindow'
+import { detail, audit } from '@/api/business/shopInfo'
+
+export default {
+  name: 'OperaShopApprovalWindow',
+  extends: BaseOpera,
+  components: { GlobalWindow },
+  data () {
+    return {
+      storeInfo: null,
+      approvalForm: {
+        id: null,
+        auditStatus: 0,
+        auditRemark: ''
+      },
+      approvalRules: {
+        auditRemark: [
+          { required: true, message: '璇疯緭鍏ユ嫆缁濆師鍥�', trigger: 'blur' }
+        ]
+      },
+      isWorking: {
+        submit: false
+      }
+    }
+  },
+  created () {
+    this.config({
+      api: '/business/shopInfo',
+      'field.id': 'id'
+    })
+  },
+  methods: {
+    open (title, row) {
+      this.title = title
+      this.approvalForm = {
+        id: row.id,
+        auditStatus: 1,
+        auditRemark: ''
+      }
+      detail(row.id)
+        .then(res => {
+          this.storeInfo = res
+          this.visible = true
+        })
+        .catch(e => {
+          this.$tip.apiFailed(e)
+        })
+    },
+    handleAuditStatusChange (val) {
+      if (val === 1) {
+        this.approvalRules.auditRemark = []
+      } else {
+        this.approvalRules.auditRemark = [{ required: true, message: '璇疯緭鍏ユ嫆缁濆師鍥�', trigger: 'blur' }]
+      }
+    },
+    handleSubmit () {
+      this.$refs.approvalForm.validate(valid => {
+        if (!valid) return
+        this.isWorking.submit = true
+        audit(this.approvalForm)
+          .then(res => {
+            this.$tip.apiSuccess(res || '鎻愪氦鎴愬姛')
+            this.visible = false
+            this.$emit('success')
+          })
+          .catch(e => {
+            this.$tip.apiFailed(e)
+          })
+          .finally(() => {
+            this.isWorking.submit = false
+          })
+      })
+    },
+    handleCancel () {
+      this.visible = false
+    }
+  }
+}
+</script>
+
+<style scoped>
+.store-header {
+  display: flex;
+  background: #f5f7fa;
+  border-radius: 8px;
+  padding: 20px;
+  margin-bottom: 20px;
+}
+.store-header-left {
+  margin-right: 20px;
+}
+.store-avatar {
+  width: 80px;
+  height: 80px;
+  border-radius: 50%;
+}
+.store-header-right {
+  flex: 1;
+}
+.store-name {
+  font-size: 18px;
+  font-weight: bold;
+  color: #303133;
+  margin-bottom: 10px;
+}
+.store-info-row {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 20px;
+}
+.info-item {
+  font-size: 14px;
+  color: #606266;
+}
+.info-item .label {
+  color: #909399;
+}
+.qualification-content {
+  padding: 20px;
+}
+.qualification-section {
+  margin-bottom: 30px;
+}
+.section-title {
+  font-size: 16px;
+  font-weight: bold;
+  color: #303133;
+  margin-bottom: 15px;
+  padding-left: 10px;
+  border-left: 4px solid #2E68EC;
+}
+.info-grid {
+  display: grid;
+  grid-template-columns: repeat(2, 1fr);
+  gap: 15px;
+  margin-bottom: 20px;
+}
+.info-row {
+  display: flex;
+  font-size: 14px;
+}
+.info-row .label {
+  color: #909399;
+  min-width: 100px;
+}
+.info-row .value {
+  color: #606266;
+}
+.image-section {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 30px;
+}
+.image-item {
+  display: flex;
+  flex-direction: column;
+}
+.image-item-row {
+  display: flex;
+  align-items: flex-start;
+  margin-bottom: 20px;
+}
+.image-item-row .label {
+  color: #909399;
+  font-size: 14px;
+  min-width: 120px;
+}
+.image-list {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 10px;
+}
+.image-item .label {
+  color: #909399;
+  font-size: 14px;
+  margin-bottom: 8px;
+}
+.qualification-image {
+  width: 150px;
+  height: 100px;
+  border-radius: 4px;
+  border: 1px solid #eee;
+}
+.image-slot {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  width: 100%;
+  height: 100%;
+  background: #f5f7fa;
+  color: #909399;
+  font-size: 20px;
+}
+.approval-section {
+  padding: 20px;
+}
+.approval-result {
+  border-radius: 8px;
+  padding: 20px;
+}
+.approval-pass {
+  background: #f0f9eb;
+  border: 1px solid #67c23a;
+}
+.approval-reject {
+  background: #fef0f0;
+  border: 1px solid #f56c6c;
+}
+.approval-status {
+  font-size: 18px;
+  font-weight: bold;
+  margin-bottom: 15px;
+  display: flex;
+  align-items: center;
+  gap: 10px;
+}
+.approval-pass .approval-status {
+  color: #67c23a;
+}
+.approval-reject .approval-status {
+  color: #f56c6c;
+}
+.approval-info {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 30px;
+  font-size: 14px;
+  color: #606266;
+}
+.approval-form {
+  padding: 20px;
+  border-top: 1px solid #eee;
+  background: #f5f7fa;
+  border-radius: 8px;
+  margin-top: 20px;
+}
+.approval-buttons {
+  margin-top: 20px;
+}
+</style>
diff --git a/admin/src/components/business/OperaShopEditWindow.vue b/admin/src/components/business/OperaShopEditWindow.vue
index f9e942c..7c3855d 100644
--- a/admin/src/components/business/OperaShopEditWindow.vue
+++ b/admin/src/components/business/OperaShopEditWindow.vue
@@ -2,11 +2,11 @@
   <GlobalWindow
     title="缂栬緫闂ㄥ簵"
     :visible.sync="visible"
-    width="60%"
+    width="600px"
     :confirm-working="isWorking.save"
     @confirm="handleConfirm"
   >
-    <el-form ref="form" :model="form" label-width="120px" :rules="rules" class="inline-form">
+    <el-form ref="form" :model="form" :rules="rules">
       <div class="form-section">
         <h4 class="section-title">璐﹀彿淇℃伅</h4>
         <el-form-item label="娉ㄥ唽鎵嬫満鍙�" prop="telephone">
@@ -307,12 +307,17 @@
       this.$refs.form.validate(valid => {
         if (!valid) return
         this.isWorking.save = true
-        const imageFields = ['businessImg', 'idcardImg', 'idcardImgBack', 'laborContractImgs', 'socialSecurityImgs', 'storeFrontImgs', 'storeInteriorImgs', 'otherMaterialImgs']
+        const imageFields = ['laborContractImgs', 'socialSecurityImgs', 'storeFrontImgs', 'storeInteriorImgs', 'otherMaterialImgs']
+        const singleImageFields = ['businessImg', 'idcardImg', 'idcardImgBack']
         const data = { ...this.form }
+        singleImageFields.forEach(field => {
+          if (data[field] && Array.isArray(data[field])) {
+            data[field] = data[field].map(item => typeof item === 'object' ? item.fileurl : item).join(',')
+          }
+        })
         imageFields.forEach(field => {
-          if (data[field]) {
-            const list = Array.isArray(data[field]) ? data[field] : [data[field]]
-            data[field] = list.map(item => typeof item === 'object' ? item.fileurl : item).join(',')
+          if (data[field] && Array.isArray(data[field])) {
+            data[field] = data[field].map(item => typeof item === 'object' ? item.fileurl : item)
           }
         })
         data.provinceId = this.form.areaCode[0] || ''
@@ -352,7 +357,7 @@
 .password-tip {
   color: #909399;
   font-size: 12px;
-  margin: -10px 0 15px 120px;
+  margin: -10px 0 15px 0;
 }
 .longitude-latitude {
   display: flex;
diff --git a/admin/src/components/business/OperaShopInfoSeeWindow.vue b/admin/src/components/business/OperaShopInfoSeeWindow.vue
new file mode 100644
index 0000000..4797669
--- /dev/null
+++ b/admin/src/components/business/OperaShopInfoSeeWindow.vue
@@ -0,0 +1,416 @@
+<template>
+  <GlobalWindow
+    :title="title"
+    :withFooter="false"
+    :visible.sync="visible"
+    width="80%"
+  >
+    <div class="store-header" v-if="storeInfo">
+      <div class="store-header-left">
+        <el-image :src="storeInfo.payMemberCoverImage ? storeInfo.imgPrefix + storeInfo.payMemberCoverImage : ''" fit="cover" class="store-avatar">
+          <div slot="error" class="image-slot">
+            <i class="el-icon-picture-outline"></i>
+          </div>
+        </el-image>
+      </div>
+      <div class="store-header-right">
+        <div class="store-name">{{ storeInfo.name }}</div>
+        <div class="store-info-row">
+          <span class="info-item">
+            <span class="label">闂ㄥ簵绫诲瀷锛�</span>
+            <span class="value">{{ storeInfo.companyType === 1 ? '浼佷笟' : '涓汉' }}</span>
+          </span>
+          <span class="info-item">
+            <span class="label">鑱旂郴浜猴細</span>
+            <span class="value">{{ storeInfo.linkName }}</span>
+          </span>
+          <span class="info-item">
+            <span class="label">鑱旂郴鐢佃瘽锛�</span>
+            <span class="value">{{ storeInfo.linkPhone }}</span>
+          </span>
+          <span class="info-item">
+            <span class="label">韬唤璇佸彿锛�</span>
+            <span class="value">{{ storeInfo.idcard }}</span>
+          </span>
+        </div>
+      </div>
+    </div>
+
+    <div class="approval-section" v-if="storeInfo && storeInfo.auditStatus !== 0">
+      <div class="approval-result" :class="storeInfo.auditStatus === 1 ? 'approval-pass' : 'approval-reject'">
+        <div class="approval-status" v-if="storeInfo.auditStatus === 1">
+          <i class="el-icon-circle-check"></i>
+          <span>瀹℃牳閫氳繃</span>
+        </div>
+        <div class="approval-status" v-else>
+          <i class="el-icon-circle-close"></i>
+          <span>瀹℃牳鎷掔粷</span>
+        </div>
+        <div class="approval-info" v-if="storeInfo.auditStatus === 1">
+          <span class="info-item">瀹℃牳鏃堕棿锛歿{ storeInfo.auditTime }}</span>
+          <span class="info-item">瀹℃牳浜猴細{{ storeInfo.auditName }}</span>
+        </div>
+        <div class="approval-info" v-else>
+          <div class="info-item" v-if="storeInfo.auditRemark">澶囨敞锛歿{ storeInfo.auditRemark }}</div>
+          <div class="info-item">瀹℃牳鏃堕棿锛歿{ storeInfo.auditTime }}</div>
+          <div class="info-item">瀹℃牳浜猴細{{ storeInfo.auditName }}</div>
+        </div>
+      </div>
+    </div>
+
+    <div class="qualification-content" v-if="storeInfo">
+      <div class="qualification-section">
+        <h4 class="section-title">鍩烘湰淇℃伅</h4>
+        <div class="info-grid">
+          <div class="info-row">
+            <span class="label">鎵�鍦ㄧ渷甯傚尯锛�</span>
+            <span class="value">{{ storeInfo.provinceName || '' }} {{ storeInfo.cityName || '' }} {{ storeInfo.areaName || '' }}</span>
+          </div>
+          <div class="info-row">
+            <span class="label">闂ㄥ簵鍦板潃锛�</span>
+            <span class="value">{{ storeInfo.address }}</span>
+          </div>
+          <div class="info-row">
+            <span class="label">闂ㄥ簵鐘舵�侊細</span>
+            <span class="value">{{ storeInfo.auditStatus === 0 ? '寰呭鎵�' : storeInfo.auditStatus === 1 ? '瀹℃壒閫氳繃' : '瀹℃壒鏈�氳繃' }}</span>
+          </div>
+          <div class="info-row">
+            <span class="label">閰嶉�佽寖鍥达細</span>
+            <span class="value">{{ storeInfo.deliveryRange || '鏆傛棤' }}</span>
+          </div>
+        </div>
+      </div>
+
+      <div class="qualification-section">
+        <h4 class="section-title">涓讳綋璧勮川</h4>
+        <template v-if="storeInfo.companyType === 1">
+          <div class="info-grid">
+            <div class="info-row">
+              <span class="label">娉曚汉濮撳悕锛�</span>
+              <span class="value">{{ storeInfo.legalPersonName }}</span>
+            </div>
+            <div class="info-row">
+              <span class="label">娉曚汉鎵嬫満鍙凤細</span>
+              <span class="value">{{ storeInfo.legalPersonPhone }}</span>
+            </div>
+            <div class="info-row">
+              <span class="label">娉曚汉韬唤璇佸彿鐮侊細</span>
+              <span class="value">{{ storeInfo.legalPersonCard }}</span>
+            </div>
+          </div>
+          <div class="image-section">
+            <div class="image-item">
+              <span class="label">娉曚汉韬唤璇佹闈細</span>
+              <el-image :src="storeInfo.idcardImg" fit="cover" class="qualification-image" :preview-src-list="[storeInfo.idcardImg]">
+                <div slot="error" class="image-slot"><i class="el-icon-picture-outline"></i></div>
+              </el-image>
+            </div>
+            <div class="image-item">
+              <span class="label">娉曚汉韬唤璇佸弽闈細</span>
+              <el-image :src="storeInfo.idcardImgBack" fit="cover" class="qualification-image" :preview-src-list="[storeInfo.idcardImgBack]">
+                <div slot="error" class="image-slot"><i class="el-icon-picture-outline"></i></div>
+              </el-image>
+            </div>
+            <div class="image-item">
+              <span class="label">钀ヤ笟鎵х収锛�</span>
+              <el-image :src="storeInfo.businessImg" fit="cover" class="qualification-image" :preview-src-list="[storeInfo.businessImg]">
+                <div slot="error" class="image-slot"><i class="el-icon-picture-outline"></i></div>
+              </el-image>
+            </div>
+          </div>
+        </template>
+        <template v-else>
+          <div class="image-item-row">
+            <span class="label">韬唤璇佹闈細</span>
+            <el-image :src="storeInfo.idcardImg" fit="cover" class="qualification-image" :preview-src-list="[storeInfo.idcardImg]">
+              <div slot="error" class="image-slot"><i class="el-icon-picture-outline"></i></div>
+            </el-image>
+          </div>
+          <div class="image-item-row">
+            <span class="label">韬唤璇佸弽闈細</span>
+            <el-image :src="storeInfo.idcardImgBack" fit="cover" class="qualification-image" :preview-src-list="[storeInfo.idcardImgBack]">
+              <div slot="error" class="image-slot"><i class="el-icon-picture-outline"></i></div>
+            </el-image>
+          </div>
+          <div class="image-item-row">
+            <span class="label">鏈夋晥鍔冲姩鍚堝悓锛�</span>
+            <div class="image-list">
+              <el-image v-for="(img, index) in storeInfo.laborContractImgs" :key="index" :src="img" fit="cover" class="qualification-image" :preview-src-list="storeInfo.laborContractImgs">
+                <div slot="error" class="image-slot"><i class="el-icon-picture-outline"></i></div>
+              </el-image>
+            </div>
+          </div>
+          <div class="image-item-row">
+            <span class="label">绀句繚缂寸撼璇佹槑锛�</span>
+            <div class="image-list">
+              <el-image v-for="(img, index) in storeInfo.socialSecurityImgs" :key="index" :src="img" fit="cover" class="qualification-image" :preview-src-list="storeInfo.socialSecurityImgs">
+                <div slot="error" class="image-slot"><i class="el-icon-picture-outline"></i></div>
+              </el-image>
+            </div>
+          </div>
+        </template>
+      </div>
+
+      <div class="qualification-section" v-if="storeInfo.companyType === 1">
+        <h4 class="section-title">闂ㄥ簵鐓х墖鍙婂叾浠栨潗鏂�</h4>
+        <div class="image-item-row">
+          <span class="label">闂ㄥ簵闂ㄥご鐓э細</span>
+          <div class="image-list">
+            <el-image v-for="(img, index) in storeInfo.storeFrontImgs" :key="index" :src="img" fit="cover" class="qualification-image" :preview-src-list="storeInfo.storeFrontImgs">
+              <div slot="error" class="image-slot"><i class="el-icon-picture-outline"></i></div>
+            </el-image>
+          </div>
+        </div>
+        <div class="image-item-row">
+          <span class="label">闂ㄥ簵鍐呴儴鐓х墖锛�</span>
+          <div class="image-list">
+            <el-image v-for="(img, index) in storeInfo.storeInteriorImgs" :key="index" :src="img" fit="cover" class="qualification-image" :preview-src-list="storeInfo.storeInteriorImgs">
+              <div slot="error" class="image-slot"><i class="el-icon-picture-outline"></i></div>
+            </el-image>
+          </div>
+        </div>
+        <div class="image-item-row">
+          <span class="label">鍏跺畠鏉愭枡锛�</span>
+          <div class="image-list">
+            <el-image v-for="(img, index) in storeInfo.otherMaterialImgs" :key="index" :src="img" fit="cover" class="qualification-image" :preview-src-list="storeInfo.otherMaterialImgs">
+              <div slot="error" class="image-slot"><i class="el-icon-picture-outline"></i></div>
+            </el-image>
+          </div>
+        </div>
+      </div>
+    </div>
+  </GlobalWindow>
+</template>
+
+<script>
+import BaseOpera from '@/components/base/BaseOpera'
+import GlobalWindow from '@/components/common/GlobalWindow'
+import { detail, audit } from '@/api/business/shopInfo'
+
+export default {
+  name: 'OperaShopInfoSeeWindow',
+  extends: BaseOpera,
+  components: { GlobalWindow },
+  data () {
+    return {
+      storeInfo: null,
+      approvalForm: {
+        id: null,
+        auditStatus: 0,
+        auditRemark: ''
+      },
+      approvalRules: {
+        auditRemark: [
+          { required: true, message: '璇疯緭鍏ユ嫆缁濆師鍥�', trigger: 'blur' }
+        ]
+      },
+      isWorking: {
+        submit: false
+      }
+    }
+  },
+  created () {
+    this.config({
+      api: '/business/shopInfo',
+      'field.id': 'id'
+    })
+  },
+  methods: {
+    open (title, row) {
+      this.title = title
+      this.approvalForm = {
+        id: row.id,
+        auditStatus: 1,
+        auditRemark: ''
+      }
+      detail(row.id)
+        .then(res => {
+          this.storeInfo = res
+          this.visible = true
+        })
+        .catch(e => {
+          this.$tip.apiFailed(e)
+        })
+    },
+    handleAuditStatusChange (val) {
+      if (val === 1) {
+        this.approvalRules.auditRemark = []
+      } else {
+        this.approvalRules.auditRemark = [{ required: true, message: '璇疯緭鍏ユ嫆缁濆師鍥�', trigger: 'blur' }]
+      }
+    },
+    handleSubmit () {
+      this.$refs.approvalForm.validate(valid => {
+        if (!valid) return
+        this.isWorking.submit = true
+        audit(this.approvalForm)
+          .then(res => {
+            this.$tip.apiSuccess(res || '鎻愪氦鎴愬姛')
+            this.visible = false
+            this.$emit('success')
+          })
+          .catch(e => {
+            this.$tip.apiFailed(e)
+          })
+          .finally(() => {
+            this.isWorking.submit = false
+          })
+      })
+    },
+    handleCancel () {
+      this.visible = false
+    }
+  }
+}
+</script>
+
+<style scoped>
+.store-header {
+  display: flex;
+  background: #f5f7fa;
+  border-radius: 8px;
+  padding: 20px;
+  margin-bottom: 20px;
+}
+.store-header-left {
+  margin-right: 20px;
+}
+.store-avatar {
+  width: 80px;
+  height: 80px;
+  border-radius: 50%;
+}
+.store-header-right {
+  flex: 1;
+}
+.store-name {
+  font-size: 18px;
+  font-weight: bold;
+  color: #303133;
+  margin-bottom: 10px;
+}
+.store-info-row {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 20px;
+}
+.info-item {
+  font-size: 14px;
+  color: #606266;
+}
+.info-item .label {
+  color: #909399;
+}
+.qualification-content {
+  padding: 20px;
+}
+.qualification-section {
+  margin-bottom: 30px;
+}
+.section-title {
+  font-size: 16px;
+  font-weight: bold;
+  color: #303133;
+  margin-bottom: 15px;
+  padding-left: 10px;
+  border-left: 4px solid #2E68EC;
+}
+.info-grid {
+  display: grid;
+  grid-template-columns: repeat(2, 1fr);
+  gap: 15px;
+  margin-bottom: 20px;
+}
+.info-row {
+  display: flex;
+  font-size: 14px;
+}
+.info-row .label {
+  color: #909399;
+  min-width: 100px;
+}
+.info-row .value {
+  color: #606266;
+}
+.image-section {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 30px;
+}
+.image-item {
+  display: flex;
+  flex-direction: column;
+}
+.image-item-row {
+  display: flex;
+  align-items: flex-start;
+  margin-bottom: 20px;
+}
+.image-item-row .label {
+  color: #909399;
+  font-size: 14px;
+  min-width: 120px;
+}
+.image-list {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 10px;
+}
+.image-item .label {
+  color: #909399;
+  font-size: 14px;
+  margin-bottom: 8px;
+}
+.qualification-image {
+  width: 150px;
+  height: 100px;
+  border-radius: 4px;
+  border: 1px solid #eee;
+}
+.image-slot {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  width: 100%;
+  height: 100%;
+  background: #f5f7fa;
+  color: #909399;
+  font-size: 20px;
+}
+.approval-section {
+  padding: 20px;
+}
+.approval-result {
+  border-radius: 8px;
+  padding: 20px;
+}
+.approval-pass {
+  background: #f0f9eb;
+  border: 1px solid #67c23a;
+}
+.approval-reject {
+  background: #fef0f0;
+  border: 1px solid #f56c6c;
+}
+.approval-status {
+  font-size: 18px;
+  font-weight: bold;
+  margin-bottom: 15px;
+  display: flex;
+  align-items: center;
+  gap: 10px;
+}
+.approval-pass .approval-status {
+  color: #67c23a;
+}
+.approval-reject .approval-status {
+  color: #f56c6c;
+}
+.approval-info {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 30px;
+  font-size: 14px;
+  color: #606266;
+}
+</style>
diff --git a/admin/src/components/business/OperaShopInfoWindow.vue b/admin/src/components/business/OperaShopInfoWindow.vue
index 55322fc..98d7223 100644
--- a/admin/src/components/business/OperaShopInfoWindow.vue
+++ b/admin/src/components/business/OperaShopInfoWindow.vue
@@ -1,16 +1,17 @@
 <template>
   <GlobalWindow
     :title="title"
+    :withFooter="false"
     :visible.sync="visible"
     width="80%"
   >
     <div class="store-header" v-if="storeInfo">
       <div class="store-header-left">
-        <!-- <el-image :src="storeInfo.headImage || defaultAvatar" fit="cover" class="store-avatar">
+        <el-image :src="storeInfo.payMemberCoverImage ? storeInfo.imgPrefix + storeInfo.payMemberCoverImage : ''" fit="cover" class="store-avatar">
           <div slot="error" class="image-slot">
             <i class="el-icon-picture-outline"></i>
           </div>
-        </el-image> -->
+        </el-image>
       </div>
       <div class="store-header-right">
         <div class="store-name">{{ storeInfo.name }}</div>
@@ -38,14 +39,14 @@
     <el-tabs v-model="activeTab" class="store-tabs">
       <el-tab-pane label="闂ㄥ簵涓氱哗" name="performance">
         <el-form ref="searchForm" :model="searchForm" inline>
-          <el-form-item label="浜ゆ槗鍙�" prop="transactionId">
-            <el-input v-model="searchForm.transactionId" clearable placeholder="璇疯緭鍏ヤ氦鏄撳彿"></el-input>
+          <el-form-item label="浜ゆ槗鍙�" prop="orderNo">
+            <el-input v-model="searchForm.orderNo" clearable placeholder="璇疯緭鍏ヤ氦鏄撳彿"></el-input>
           </el-form-item>
-          <el-form-item label="鏀舵敮绫诲瀷" prop="type">
-            <el-select v-model="searchForm.type" clearable placeholder="璇烽�夋嫨绫诲瀷">
-              <el-option label="鍏ㄩ儴" :value="0"></el-option>
+          <el-form-item label="鏀舵敮绫诲瀷" prop="optType">
+            <el-select v-model="searchForm.optType" clearable placeholder="璇烽�夋嫨绫诲瀷">
+              <el-option label="鍏ㄩ儴" value=""></el-option>
               <el-option label="鏀跺叆" :value="1"></el-option>
-              <el-option label="鏀嚭" :value="2"></el-option>
+              <el-option label="鏀嚭" :value="-1"></el-option>
             </el-select>
           </el-form-item>
           <el-form-item label="鏀舵敮鏃堕棿" prop="createTime">
@@ -62,26 +63,32 @@
         <el-table :data="tableData.list" border stripe v-loading="isWorking.search" class="performance-table">
           <el-table-column label="鏀跺叆/鏀嚭" min-width="100px">
             <template slot-scope="{row}">
-              <span :class="row.type === 1 ? 'income' : 'expense'">{{ row.type === 1 ? '鏀跺叆' : '鏀嚭' }}</span>
+              <span :class="row.optType === 1 ? 'income' : 'expense'">{{ row.optType === 1 ? '鏀跺叆' : '鏀嚭' }}</span>
             </template>
           </el-table-column>
           <el-table-column prop="amount" label="閲戦锛堝厓锛�" min-width="100px">
             <template slot-scope="{row}">
-              <span :class="row.type === 1 ? 'income' : 'expense'">{{ row.amount }}</span>
+              <span :class="row.optType === 1 ? 'income' : 'expense'">{{ row.amount }}</span>
             </template>
           </el-table-column>
           <el-table-column prop="createTime" label="鏀舵敮鏃堕棿" min-width="160px"></el-table-column>
-          <el-table-column prop="businessType" label="涓氬姟绫诲瀷" min-width="100px"></el-table-column>
-          <el-table-column prop="transactionId" label="浜ゆ槗鍙�" min-width="180px"></el-table-column>
+          <el-table-column label="涓氬姟绫诲瀷" min-width="100px">
+            <template slot-scope="{row}">
+              <span v-if="row.type === 0">瀹屾垚璁㈠崟</span>
+              <span v-if="row.type === 1">鎻愮幇鏀嚭</span>
+              <span v-if="row.type === 2">鎻愮幇閫�鍥�</span>
+              <span v-if="row.type === 3">骞冲彴濂栧姳</span>
+            </template>
+          </el-table-column>
+          <el-table-column prop="orderNo" label="浜ゆ槗鍙�" min-width="180px"></el-table-column>
           <el-table-column label="鐘舵��" min-width="100px">
             <template slot-scope="{row}">
-              <span :class="row.status === 1 ? 'status-success' : 'status-pending'">
-                {{ row.status === 1 ? '宸插埌璐�' : '鎻愮幇涓�' }}
+              <span :class="row.vaildStatus === 1 ? 'status-success' : 'status-pending'">
+                {{ row.vaildStatus === 1 ? '宸插埌璐�' : '鎻愮幇涓�' }}
               </span>
             </template>
           </el-table-column>
         </el-table>
-
         <pagination
           @size-change="handleSizeChange"
           @current-change="handlePageChange"
@@ -221,6 +228,7 @@
 import GlobalWindow from '@/components/common/GlobalWindow'
 import Pagination from '@/components/common/Pagination'
 import { detail } from '@/api/business/shopInfo'
+import { fetchList, exportExcel } from '@/api/business/revenue'
 export default {
   name: 'OperaShopInfoWindow',
   extends: BaseOpera,
@@ -230,9 +238,11 @@
       activeTab: 'performance',
       storeInfo: null,
       searchForm: {
-        transactionId: '',
-        type: 0,
-        createTime: ''
+        orderNo: '',
+        optType: 0,
+        createTime: '',
+        memberId: '',
+        memberType: 2
       },
       tableData: {
         list: [],
@@ -257,14 +267,17 @@
   },
   methods: {
     open (title, row) {
+      this.searchForm.memberId = row.id
       detail(row.id)
         .then(res => {
           this.storeInfo = res
           this.activeTab = 'performance'
           this.searchForm = {
-            transactionId: '',
-            type: 0,
-            createTime: ''
+            orderNo: '',
+            optType: '',
+            createTime: '',
+            memberId: '',
+            memberType: 2
           }
           this.title = title
           this.visible = true
@@ -277,15 +290,18 @@
     search () {
       this.isWorking.search = true
       const data = {
-        pageIndex: this.tableData.pagination.pageIndex,
-        pageSize: this.tableData.pagination.pageSize,
-        shopId: this.storeInfo?.id,
-        transactionId: this.searchForm.transactionId,
-        type: this.searchForm.type,
-        startTime: this.searchForm.createTime?.[0] || '',
-        endTime: this.searchForm.createTime?.[1] || ''
+        capacity: this.tableData.pagination.pageSize,
+        page: this.tableData.pagination.pageIndex,
+        model: {
+          orderNo: this.searchForm.orderNo,
+          optType: this.searchForm.optType,
+          startTime: this.searchForm.createTime?.[0] || '',
+          endTime: this.searchForm.createTime?.[1] || '',
+          memberId: this.searchForm.memberId,
+          memberType: this.searchForm.memberType || ''
+        }
       }
-      this.api.fetchPerformance(data)
+      fetchList(data)
         .then(res => {
           this.tableData.list = res.list || []
           this.tableData.pagination.total = res.total || 0
@@ -299,9 +315,11 @@
     },
     reset () {
       this.searchForm = {
-        transactionId: '',
-        type: 0,
-        createTime: ''
+        orderNo: '',
+        optType: '',
+        createTime: '',
+        memberId: '',
+        memberType: 2
       }
       this.search()
     },
@@ -316,14 +334,20 @@
     exportExcel () {
       this.isWorking.export = true
       const data = {
-        shopId: this.storeInfo?.id,
-        transactionId: this.searchForm.transactionId,
-        type: this.searchForm.type,
-        startTime: this.searchForm.createTime?.[0] || '',
-        endTime: this.searchForm.createTime?.[1] || ''
+        capacity: 999999,
+        page: this.tableData.pagination.pageIndex,
+        model: {
+          orderNo: this.searchForm.orderNo,
+          optType: this.searchForm.optType,
+          startTime: this.searchForm.createTime?.[0] || '',
+          endTime: this.searchForm.createTime?.[1] || '',
+          memberId: this.searchForm.memberId,
+          memberType: this.searchForm.memberType || ''
+        }
       }
-      this.api.exportPerformance(data)
+      exportExcel(data)
         .then(res => {
+          this.download(res)
           this.$tip.apiSuccess('瀵煎嚭鎴愬姛')
         })
         .catch(e => {
diff --git a/admin/src/components/business/OperaWithdrawDetailWindow.vue b/admin/src/components/business/OperaWithdrawDetailWindow.vue
new file mode 100644
index 0000000..0d60c66
--- /dev/null
+++ b/admin/src/components/business/OperaWithdrawDetailWindow.vue
@@ -0,0 +1,297 @@
+<template>
+  <GlobalWindow
+    :title="title"
+    :visible.sync="visible"
+    :withFooter="false"
+    width="70%"
+    :confirm-working="isWorking.submit"
+    @confirm="handleConfirm"
+  >
+    <div class="detail-container">
+      <div class="section">
+        <div class="section-header">
+          <span class="section-title">鍩烘湰淇℃伅</span>
+          <span class="status-tag" :class="getStatusClass(detailInfo.status)">
+            {{ getStatusText(detailInfo.status) }}
+          </span>
+        </div>
+        <div class="info-grid">
+          <div class="info-item">
+            <span class="label">闂ㄥ簵鍚嶇О锛�</span>
+            <span class="value">{{ detailInfo.shopName }}</span>
+          </div>
+          <div class="info-item">
+            <span class="label">闂ㄥ簵鑱旂郴浜猴細</span>
+            <span class="value">{{ detailInfo.linkName }}</span>
+          </div>
+          <div class="info-item">
+            <span class="label">鐢宠鏃堕棿锛�</span>
+            <span class="value">{{ detailInfo.createTime }}</span>
+          </div>
+        </div>
+      </div>
+
+      <div class="section">
+        <div class="section-header">
+          <span class="section-title">鎻愮幇淇℃伅</span>
+        </div>
+        <div class="info-grid">
+          <div class="info-item">
+            <span class="label">鎻愮幇閲戦锛�</span>
+            <span class="value amount">楼{{ detailInfo.amount / 100 }}</span>
+          </div>
+          <div class="info-item">
+            <span class="label">鎻愮幇璐︽埛锛�</span>
+            <span class="value">{{ detailInfo.aliAccount }}</span>
+          </div>
+          <div class="info-item">
+            <span class="label">瀹℃牳浜猴細</span>
+            <span class="value">{{ detailInfo.updateUserName }}</span>
+          </div>
+          <div class="info-item">
+            <span class="label">瀹℃牳鏃堕棿锛�</span>
+            <span class="value">{{ detailInfo.updateTime }}</span>
+          </div>
+          <div class="info-item full-width">
+            <span class="label">瀹℃牳澶囨敞锛�</span>
+            <span class="value">{{ detailInfo.approveRemark }}</span>
+          </div>
+        </div>
+      </div>
+
+      <div class="section" v-if="detailInfo.status !== 0">
+        <div class="section-header">
+          <span class="section-title">瀹℃壒淇℃伅</span>
+        </div>
+        <div class="info-grid">
+          <div class="info-item">
+            <span class="label">瀹℃牳浜猴細</span>
+            <span class="value">{{ detailInfo.updateUserName }}</span>
+          </div>
+          <div class="info-item">
+            <span class="label">瀹℃牳鏃堕棿锛�</span>
+            <span class="value">{{ detailInfo.updateTime }}</span>
+          </div>
+          <div class="info-item full-width">
+            <span class="label">瀹℃牳澶囨敞锛�</span>
+            <span class="value">{{ detailInfo.approveRemark }}</span>
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <div class="approval-form" v-if="detailInfo.status === 0">
+      <el-form ref="approvalForm" :model="approvalForm" :rules="approvalRules">
+        <el-form-item label="瀹℃壒缁撴灉" prop="status">
+          <el-radio-group v-model="approvalForm.status">
+            <el-radio :label="1">閫氳繃</el-radio>
+            <el-radio :label="2">椹冲洖</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="澶囨敞" prop="approveRemark">
+          <el-input
+            v-model="approvalForm.approveRemark"
+            type="textarea"
+            :rows="3"
+            placeholder="璇疯緭鍏ュ娉�"
+            style="width: 100%"
+          ></el-input>
+        </el-form-item>
+      </el-form>
+      <div class="approval-buttons">
+        <el-button @click="visible = false">鍙栨秷</el-button>
+        <el-button type="primary" @click="handleConfirm" :loading="isWorking.submit">纭畾</el-button>
+      </div>
+    </div>
+  </GlobalWindow>
+</template>
+
+<script>
+import GlobalWindow from '@/components/common/GlobalWindow'
+import { getById, approve } from '@/api/business/shopWithdraw'
+
+export default {
+  name: 'OperaWithdrawDetailWindow',
+  components: { GlobalWindow },
+  data () {
+    return {
+      title: '鎻愮幇璇︽儏',
+      visible: false,
+      detailInfo: {
+        status: '',
+        shopName: '',
+        linkName: '',
+        createTime: '',
+        amount: '',
+        bankCardNo: '',
+        auditLogs: []
+      },
+      approvalForm: {
+        id: null,
+        status: 1,
+        approveRemark: ''
+      },
+      approvalRules: {
+        status: [{ required: true, message: '璇烽�夋嫨瀹℃壒缁撴灉', trigger: 'change' }]
+      },
+      isWorking: {
+        submit: false
+      }
+    }
+  },
+  methods: {
+    open (title, row) {
+      this.title = title
+      this.approvalForm.id = row.id
+      this.approvalForm.status = 1
+      this.approvalForm.approveRemark = ''
+      getById(row.id).then(res => {
+        this.detailInfo = {
+          status: res.status,
+          shopName: res.shopName,
+          linkName: res.linkName,
+          createTime: res.createTime,
+          amount: res.amount,
+          bankCardNo: res.bankCardNo,
+          auditLogs: res.auditLogs || [],
+          updateUserName: res.updateUserName,
+          updateTime: res.updateTime,
+          approveRemark: res.approveRemark
+        }
+        this.visible = true
+      }).catch(e => {
+        this.$tip.apiFailed(e)
+      })
+    },
+    getStatusText (status) {
+      const map = { 0: '鎻愮幇鐢宠涓�', 1: '鎻愮幇鎴愬姛', 2: '鎻愮幇澶辫触' }
+      return map[status] || '-'
+    },
+    getStatusClass (status) {
+      const map = { 0: 'status-pending', 1: 'status-success', 2: 'status-reject' }
+      return map[status] || ''
+    },
+    handleConfirm () {
+      if (this.detailInfo.status !== 0) {
+        this.visible = false
+        return
+      }
+      this.$refs.approvalForm.validate(valid => {
+        if (!valid) return
+        this.isWorking.submit = true
+        approve(this.approvalForm).then(res => {
+          this.$tip.apiSuccess(res || '鎻愪氦鎴愬姛')
+          this.visible = false
+          this.$emit('success')
+        }).catch(e => {
+          this.$tip.apiFailed(e)
+        }).finally(() => {
+          this.isWorking.submit = false
+        })
+      })
+    }
+  }
+}
+</script>
+
+<style scoped>
+.detail-container {
+  padding: 20px;
+}
+.section {
+  margin-bottom: 30px;
+}
+.section-header {
+  display: flex;
+  align-items: center;
+  gap: 15px;
+  margin-bottom: 15px;
+}
+.section-title {
+  font-size: 16px;
+  font-weight: bold;
+  color: #303133;
+  padding-left: 10px;
+  border-left: 4px solid #2E68EC;
+}
+.status-tag {
+  padding: 4px 12px;
+  border-radius: 4px;
+  font-size: 12px;
+}
+.status-pending {
+  background: #fdf6ec;
+  color: #E6A23C;
+}
+.status-success {
+  background: #f0f9eb;
+  color: #67C23A;
+}
+.status-reject {
+  background: #fef0f0;
+  color: #F56C6C;
+}
+.info-grid {
+  display: grid;
+  grid-template-columns: repeat(2, 1fr);
+  gap: 15px;
+  padding: 0 10px;
+}
+.info-item {
+  display: flex;
+  font-size: 14px;
+}
+.info-item .label {
+  color: #909399;
+  min-width: 90px;
+}
+.info-item .value {
+  color: #606266;
+}
+.info-item .amount {
+  color: #f56c6c;
+  font-weight: bold;
+}
+.info-item.full-width {
+  grid-column: span 2;
+}
+.timeline-content {
+  padding: 10px;
+  background: #f5f7fa;
+  border-radius: 4px;
+}
+.timeline-title {
+  font-size: 14px;
+  font-weight: bold;
+  color: #303133;
+  margin-bottom: 8px;
+}
+.timeline-info {
+  display: flex;
+  gap: 20px;
+  font-size: 13px;
+  color: #606266;
+  margin-bottom: 5px;
+}
+.timeline-remark {
+  font-size: 13px;
+  color: #909399;
+}
+.approval-form {
+  padding: 20px;
+  background: #f5f7fa;
+  border-top: 1px solid #eee;
+}
+.approval-form /deep/ .el-form-item {
+  margin-bottom: 15px;
+}
+.approval-form /deep/ .el-form-item:last-child {
+  margin-bottom: 0;
+}
+.approval-buttons {
+  display: flex;
+  justify-content: flex-end;
+  gap: 10px;
+  margin-top: 15px;
+}
+</style>
diff --git a/admin/src/views/business/baggageType.vue b/admin/src/views/business/baggageType.vue
new file mode 100644
index 0000000..b210bae
--- /dev/null
+++ b/admin/src/views/business/baggageType.vue
@@ -0,0 +1,96 @@
+<template>
+  <TableLayout :permissions="['business:category:query']">
+    <el-form ref="searchForm" slot="search-form" :model="searchForm" label-width="100px" inline>
+      <el-form-item label="鍚嶇О" prop="name">
+        <el-input v-model="searchForm.name" clearable placeholder="璇疯緭鍏ュ悕绉�" @keypress.enter.native="search"></el-input>
+      </el-form-item>
+      <section>
+        <el-button type="primary" @click="search">鎼滅储</el-button>
+        <el-button @click="reset">閲嶇疆</el-button>
+      </section>
+    </el-form>
+    <template v-slot:table-wrap>
+      <ul class="toolbar">
+        <li><el-button type="primary" @click="$refs.operaGoodsCategoryEditWindow.open('鏂板缓鐗╁搧绛夌骇', null, 4)" icon="el-icon-plus">鏂板缓</el-button></li>
+      </ul>
+      <el-table
+        :height="tableHeightNew"
+        v-loading="isWorking.search"
+        :data="tableData.list"
+        stripe
+      >
+        <el-table-column prop="id" label="ID" min-width="80px"></el-table-column>
+        <el-table-column prop="name" label="琛屾潕绫诲瀷" min-width="120px"></el-table-column>
+        <el-table-column prop="remark" label="澶囨敞璇存槑" min-width="200px"></el-table-column>
+        <el-table-column prop="sortnum" label="鎺掑簭" min-width="100px"></el-table-column>
+        <el-table-column prop="createTime" label="鎻愪氦鏃堕棿" min-width="100px"></el-table-column>
+        <el-table-column label="鐘舵��" min-width="80px">
+          <template slot-scope="{row}">
+            <el-switch
+              @change="handleStatusChange($event, row)"
+              v-model="row.status"
+              active-color="#13ce66"
+              inactive-color="#ff4949"
+              :active-value="0"
+              :inactive-value="1"
+            ></el-switch>
+          </template>
+        </el-table-column>
+        <el-table-column label="鎿嶄綔" min-width="150" fixed="right">
+          <template slot-scope="{row}">
+            <el-button type="text" @click="handleEdit(row)">缂栬緫</el-button>
+            <el-button type="text" @click="deleteById(row.id)">鍒犻櫎</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <pagination
+        @size-change="handleSizeChange"
+        @current-change="handlePageChange"
+        :pagination="tableData.pagination"
+      ></pagination>
+    </template>
+    <OperaGoodsCategoryEditWindow ref="operaGoodsCategoryEditWindow" @success="search" />
+  </TableLayout>
+</template>
+
+<script>
+import BaseTable from '@/components/base/BaseTable'
+import TableLayout from '@/layouts/TableLayout'
+import Pagination from '@/components/common/Pagination'
+import OperaGoodsCategoryEditWindow from '@/components/business/OperaGoodsCategoryEditWindow'
+import { updateStatus } from '@/api/business/goodsCategory'
+
+export default {
+  name: 'BaggageTypeList',
+  extends: BaseTable,
+  components: { TableLayout, Pagination, OperaGoodsCategoryEditWindow },
+  data () {
+    return {
+      searchForm: {
+        name: '',
+        type: 4
+      }
+    }
+  },
+  created () {
+    this.config({
+      api: '/business/goodsCategory',
+      'field.id': 'id'
+    })
+    this.search()
+  },
+  methods: {
+    handleEdit (row) {
+      this.$refs.operaGoodsCategoryEditWindow.open('缂栬緫鐗╁搧绛夌骇', row, 4)
+    },
+    handleStatusChange (val, row) {
+      updateStatus({ id: row.id, status: val }).then(res => {
+        this.$tip.apiSuccess(res || '淇敼鎴愬姛')
+      }).catch(e => {
+        row.status = val === 1 ? 0 : 1
+        this.$tip.apiFailed(e)
+      })
+    }
+  }
+}
+</script>
diff --git a/admin/src/views/business/bannerList.vue b/admin/src/views/business/bannerList.vue
new file mode 100644
index 0000000..3fca071
--- /dev/null
+++ b/admin/src/views/business/bannerList.vue
@@ -0,0 +1,138 @@
+<template>
+  <TableLayout :permissions="['business:banner:query']">
+    <el-form ref="searchForm" slot="search-form" :model="searchForm" label-width="100px" inline>
+      <el-form-item label="鏍囬" prop="title">
+        <el-input v-model="searchForm.title" clearable placeholder="璇疯緭鍏ユ爣棰�" @keypress.enter.native="search"></el-input>
+      </el-form-item>
+      <section>
+        <el-button type="primary" @click="search">鎼滅储</el-button>
+        <el-button @click="reset">閲嶇疆</el-button>
+      </section>
+    </el-form>
+    <template v-slot:table-wrap>
+      <ul class="toolbar" v-permissions="['business:banner:create']">
+        <li><el-button type="primary" @click="$refs.operaBannerEditWindow.open('鏂板缓杞挱鍥�',null,searchForm.type)" icon="el-icon-plus" v-permissions="['business:banner:create']">鏂板缓</el-button></li>
+      </ul>
+      <el-table
+        :height="tableHeightNew"
+        v-loading="isWorking.search"
+        :data="tableData.list"
+        stripe
+      >
+        <el-table-column prop="title" label="鏍囬" min-width="120px"></el-table-column>
+        <el-table-column prop="position" label="灞曠ず浣嶇疆" min-width="100px">
+          <template slot-scope="{row}">
+            {{ positionOptions[row.position] || '-' }}
+          </template>
+        </el-table-column>
+        <el-table-column label="鍥剧墖" min-width="120px">
+          <template slot-scope="{row}">
+            <el-image
+              v-if="row.imgurlFull"
+              style="width: 80px; height: 40px"
+              :src="row.imgurlFull"
+              fit="contain"
+            ></el-image>
+            <span v-else>-</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="璺宠浆鏂瑰紡" min-width="100px">
+          <template slot-scope="{row}">
+            {{ jumpTypeOptions[row.type] || '-' }}
+          </template>
+        </el-table-column>
+        <el-table-column prop="sortnum" label="鎺掑簭鐮�" min-width="80px"></el-table-column>
+        <el-table-column label="鐘舵��" min-width="80px">
+          <template slot-scope="{row}">
+            <el-switch
+              @change="handleStatusChange($event, row)"
+              v-model="row.status"
+              active-color="#13ce66"
+              inactive-color="#ff4949"
+              :active-value="1"
+              :inactive-value="0"
+            ></el-switch>
+          </template>
+        </el-table-column>
+        <el-table-column prop="updateTime" label="淇敼鏃堕棿" min-width="160px"></el-table-column>
+        <el-table-column label="鎿嶄綔" min-width="150" fixed="right">
+          <template slot-scope="{row}">
+            <el-button type="text" @click="handleEdit(row)">缂栬緫</el-button>
+            <el-button type="text" @click="deleteById(row.id)">鍒犻櫎</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <pagination
+        @size-change="handleSizeChange"
+        @current-change="handlePageChange"
+        :pagination="tableData.pagination"
+      ></pagination>
+    </template>
+    <OperaBannerEditWindow ref="operaBannerEditWindow" @success="search" />
+  </TableLayout>
+</template>
+
+<script>
+import BaseTable from '@/components/base/BaseTable'
+import TableLayout from '@/layouts/TableLayout'
+import Pagination from '@/components/common/Pagination'
+import OperaBannerEditWindow from '@/components/business/OperaBannerEditWindow'
+import { updateById, deleteById } from '@/api/business/banner'
+
+export default {
+  name: 'BannerList',
+  extends: BaseTable,
+  components: { TableLayout, Pagination, OperaBannerEditWindow },
+  data () {
+    return {
+      positionOptions: {
+        0: '棣栭〉',
+        1: '搴楅摵棣栭〉'
+      },
+      jumpTypeOptions: {
+        0: '鏃�',
+        1: '浼氬憳绔椤佃疆鎾�',
+        2: '鍙告満APP寮曞椤�'
+      },
+      searchForm: {
+        title: ''
+      }
+    }
+  },
+  created () {
+    this.config({
+      api: '/business/banner',
+      'field.id': 'id'
+    })
+    this.search()
+  },
+  methods: {
+    loadTableData (resolve) {
+      this.isWorking.search = true
+      list(this.getTableParams())
+        .then(data => {
+          this.tableData.list = data.list || []
+          this.tableData.pagination.total = data.total || 0
+          if (resolve) resolve(data)
+        })
+        .catch(e => {
+          this.$tip.apiFailed(e, '鍔犺浇澶辫触')
+        })
+        .finally(() => {
+          this.isWorking.search = false
+        })
+    },
+    handleEdit (row) {
+      this.$refs.operaBannerEditWindow.open('缂栬緫杞挱鍥�', row)
+    },
+    handleStatusChange (val, row) {
+      updateById({ id: row.id, status: val }).then(res => {
+        this.$tip.apiSuccess(res || '淇敼鎴愬姛')
+      }).catch(e => {
+        row.status = val === 1 ? 0 : 1
+        this.$tip.apiFailed(e)
+      })
+    }
+  }
+}
+</script>
diff --git a/admin/src/views/business/driverList.vue b/admin/src/views/business/driverList.vue
new file mode 100644
index 0000000..52fdbdd
--- /dev/null
+++ b/admin/src/views/business/driverList.vue
@@ -0,0 +1,167 @@
+<template>
+  <TableLayout :permissions="['business:driver:query']">
+    <el-form ref="searchForm" slot="search-form" :model="searchForm" label-width="100px" inline>
+      <el-form-item label="鍙告満淇℃伅" prop="keyword">
+        <el-input v-model="searchForm.keyword" clearable placeholder="璇疯緭鍏ュ徃鏈哄鍚�/鎵嬫満鍙�" @keypress.enter.native="search"></el-input>
+      </el-form-item>
+      <el-form-item label="杞︾墝鍙�" prop="carNo">
+        <el-input v-model="searchForm.carNo" clearable placeholder="璇疯緭鍏ヨ溅鐗屽彿" @keypress.enter.native="search"></el-input>
+      </el-form-item>
+      <el-form-item label="鐘舵��" prop="status">
+        <el-select v-model="searchForm.status" clearable placeholder="璇烽�夋嫨鐘舵��" @change="search">
+          <el-option label="绂佺敤" :value="0"></el-option>
+          <el-option label="鍚敤" :value="1"></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="鎬у埆" prop="sex">
+        <el-select v-model="searchForm.sex" clearable placeholder="璇烽�夋嫨鎬у埆" @change="search">
+          <el-option label="鐢�" :value="1"></el-option>
+          <el-option label="濂�" :value="2"></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="鍒涘缓鏃堕棿" prop="createTime">
+        <el-date-picker type="daterange" v-model="searchForm.createTime" clearable value-format="yyyy-MM-dd"
+                        range-separator="-" start-placeholder="寮�濮嬫棩鏈�" end-placeholder="缁撴潫鏃ユ湡" @change="handleDateChange" />
+      </el-form-item>
+      <section>
+        <el-button type="primary" @click="search">鎼滅储</el-button>
+        <el-button @click="reset">閲嶇疆</el-button>
+        <el-button :loading="isWorking.export" @click="handleExport">瀵煎嚭</el-button>
+      </section>
+    </el-form>
+    <template v-slot:table-wrap>
+      <el-table
+        :height="tableHeightNew"
+        v-loading="isWorking.search"
+        :data="tableData.list"
+        stripe
+      >
+        <el-table-column prop="nickName" label="鐢ㄦ埛鏄电О" min-width="100px"></el-table-column>
+        <el-table-column prop="name" label="鍙告満濮撳悕" min-width="100px"></el-table-column>
+        <el-table-column label="鎬у埆" min-width="60px">
+          <template slot-scope="{row}">{{ row.sex === 1 ? '鐢�' : row.sex === 2 ? '濂�' : '-' }}</template>
+        </el-table-column>
+        <el-table-column prop="phone" label="娉ㄥ唽鎵嬫満鍙�" min-width="120px"></el-table-column>
+        <el-table-column prop="idCard" label="韬唤璇佸彿" min-width="160px"></el-table-column>
+        <el-table-column label="璐︽埛浣欓" min-width="100px">
+          <template slot-scope="{row}">楼{{ (row.amount / 100).toFixed(2) }}</template>
+        </el-table-column>
+        <el-table-column prop="carNo" label="杞︾墝鍙�" min-width="100px"></el-table-column>
+        <el-table-column prop="createTime" label="鍒涘缓鏃堕棿" min-width="160px"></el-table-column>
+        <el-table-column label="鐘舵��" min-width="80px">
+          <template slot-scope="{row}">
+            <el-switch
+              @change="handleStatusChange($event, row)"
+              v-model="row.status"
+              active-color="#13ce66"
+              inactive-color="#ff4949"
+              :active-value="1"
+              :inactive-value="0"
+            ></el-switch>
+          </template>
+        </el-table-column>
+        <el-table-column label="鎿嶄綔" min-width="100" fixed="right">
+          <template slot-scope="{row}">
+            <el-button type="text" @click="handleDetail(row)">璇︽儏</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <pagination
+        @size-change="handleSizeChange"
+        @current-change="handlePageChange"
+        :pagination="tableData.pagination"
+      ></pagination>
+    </template>
+  </TableLayout>
+</template>
+
+<script>
+import BaseTable from '@/components/base/BaseTable'
+import TableLayout from '@/layouts/TableLayout'
+import Pagination from '@/components/common/Pagination'
+import { fetchList, updateStatus, exportExcel } from '@/api/business/driver'
+
+export default {
+  name: 'DriverList',
+  extends: BaseTable,
+  components: { TableLayout, Pagination },
+  data () {
+    return {
+      searchForm: {
+        keyword: '',
+        carNo: '',
+        status: '',
+        sex: '',
+        createTime: '',
+        startTime: '',
+        endTime: ''
+      }
+    }
+  },
+  created () {
+    this.config({
+      api: '/business/driver',
+      'field.id': 'id'
+    })
+    this.search()
+  },
+  methods: {
+    loadTableData (resolve) {
+      this.isWorking.search = true
+      fetchList(this.getTableParams())
+        .then(data => {
+          this.tableData.list = data.list || []
+          this.tableData.pagination.total = data.total || 0
+          if (resolve) resolve(data)
+        })
+        .catch(e => {
+          this.$tip.apiFailed(e, '鍔犺浇澶辫触')
+        })
+        .finally(() => {
+          this.isWorking.search = false
+        })
+    },
+    handleDateChange (val) {
+      this.searchForm.startTime = val ? val[0] : ''
+      this.searchForm.endTime = val ? val[1] : ''
+      this.search()
+    },
+    reset () {
+      this.searchForm = {
+        keyword: '',
+        carNo: '',
+        status: '',
+        sex: '',
+        createTime: '',
+        startTime: '',
+        endTime: ''
+      }
+      this.search()
+    },
+    handleDetail (row) {
+    },
+    handleStatusChange (val, row) {
+      updateStatus({ id: row.id, status: val }).then(res => {
+        this.$tip.apiSuccess(res || '淇敼鎴愬姛')
+      }).catch(e => {
+        row.status = val === 1 ? 0 : 1
+        this.$tip.apiFailed(e)
+      })
+    },
+    handleExport () {
+      this.isWorking.export = true
+      exportExcel(this.getTableParams())
+        .then(res => {
+          this.download(res)
+          this.$tip.apiSuccess('瀵煎嚭鎴愬姛')
+        })
+        .catch(e => {
+          this.$tip.apiFailed(e)
+        })
+        .finally(() => {
+          this.isWorking.export = false
+        })
+    }
+  }
+}
+</script>
diff --git a/admin/src/views/business/goodsCategoryList.vue b/admin/src/views/business/goodsCategoryList.vue
new file mode 100644
index 0000000..d09308c
--- /dev/null
+++ b/admin/src/views/business/goodsCategoryList.vue
@@ -0,0 +1,96 @@
+<template>
+  <TableLayout :permissions="['business:category:query']">
+    <el-form ref="searchForm" slot="search-form" :model="searchForm" label-width="100px" inline>
+      <el-form-item label="鍚嶇О" prop="name">
+        <el-input v-model="searchForm.name" clearable placeholder="璇疯緭鍏ュ悕绉�" @keypress.enter.native="search"></el-input>
+      </el-form-item>
+      <section>
+        <el-button type="primary" @click="search">鎼滅储</el-button>
+        <el-button @click="reset">閲嶇疆</el-button>
+      </section>
+    </el-form>
+    <template v-slot:table-wrap>
+      <ul class="toolbar">
+        <li><el-button type="primary" @click="$refs.operaGoodsCategoryEditWindow.open('鏂板缓鐗╁搧鍒嗙被', null, 2)" icon="el-icon-plus">鏂板缓</el-button></li>
+      </ul>
+      <el-table
+        :height="tableHeightNew"
+        v-loading="isWorking.search"
+        :data="tableData.list"
+        stripe
+      >
+        <el-table-column prop="id" label="ID" min-width="80px"></el-table-column>
+        <el-table-column prop="name" label="鐗╁搧鍚嶇О" min-width="120px"></el-table-column>
+        <el-table-column prop="detail" label="瀵勫瓨璇存槑" min-width="200px"></el-table-column>
+        <el-table-column prop="sortnum" label="鍒嗙被鎺掑簭" min-width="100px"></el-table-column>
+        <el-table-column label="鐘舵��" min-width="80px">
+          <template slot-scope="{row}">
+            <el-switch
+              @change="handleStatusChange($event, row)"
+              v-model="row.status"
+              active-color="#13ce66"
+              inactive-color="#ff4949"
+              :active-value="0"
+              :inactive-value="1"
+            ></el-switch>
+          </template>
+        </el-table-column>
+        <el-table-column label="鎿嶄綔" min-width="150" fixed="right">
+          <template slot-scope="{row}">
+            <el-button type="text" @click="handleEdit(row)">缂栬緫</el-button>
+            <el-button type="text" @click="deleteById(row.id)">鍒犻櫎</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <pagination
+        @size-change="handleSizeChange"
+        @current-change="handlePageChange"
+        :pagination="tableData.pagination"
+      ></pagination>
+    </template>
+    <OperaGoodsCategoryEditWindow ref="operaGoodsCategoryEditWindow" @success="search" />
+  </TableLayout>
+</template>
+
+<script>
+import BaseTable from '@/components/base/BaseTable'
+import TableLayout from '@/layouts/TableLayout'
+import Pagination from '@/components/common/Pagination'
+import OperaGoodsCategoryEditWindow from '@/components/business/OperaGoodsCategoryEditWindow'
+import { fetchList, updateStatus, deleteById } from '@/api/business/goodsCategory'
+
+export default {
+  name: 'GoodsCategoryList',
+  extends: BaseTable,
+  components: { TableLayout, Pagination, OperaGoodsCategoryEditWindow },
+  data () {
+    return {
+      searchForm: {
+        name: '',
+        status: '',
+        type: 2
+      }
+    }
+  },
+  created () {
+    this.config({
+      api: '/business/goodsCategory',
+      'field.id': 'id'
+    })
+    this.search()
+  },
+  methods: {
+    handleEdit (row) {
+      this.$refs.operaGoodsCategoryEditWindow.open('缂栬緫鐗╁搧鍒嗙被', row, 2)
+    },
+    handleStatusChange (val, row) {
+      updateStatus({ id: row.id, status: val }).then(res => {
+        this.$tip.apiSuccess(res || '淇敼鎴愬姛')
+      }).catch(e => {
+        row.status = val === 1 ? 0 : 1
+        this.$tip.apiFailed(e)
+      })
+    }
+  }
+}
+</script>
diff --git a/admin/src/views/business/itemLevel.vue b/admin/src/views/business/itemLevel.vue
new file mode 100644
index 0000000..65a47b6
--- /dev/null
+++ b/admin/src/views/business/itemLevel.vue
@@ -0,0 +1,96 @@
+<template>
+  <TableLayout :permissions="['business:category:query']">
+    <el-form ref="searchForm" slot="search-form" :model="searchForm" label-width="100px" inline>
+      <el-form-item label="鍚嶇О" prop="name">
+        <el-input v-model="searchForm.name" clearable placeholder="璇疯緭鍏ュ悕绉�" @keypress.enter.native="search"></el-input>
+      </el-form-item>
+      <section>
+        <el-button type="primary" @click="search">鎼滅储</el-button>
+        <el-button @click="reset">閲嶇疆</el-button>
+      </section>
+    </el-form>
+    <template v-slot:table-wrap>
+      <ul class="toolbar">
+        <li><el-button type="primary" @click="$refs.operaGoodsCategoryEditWindow.open('鏂板缓鐗╁搧绛夌骇', null, 3)" icon="el-icon-plus">鏂板缓</el-button></li>
+      </ul>
+      <el-table
+        :height="tableHeightNew"
+        v-loading="isWorking.search"
+        :data="tableData.list"
+        stripe
+      >
+        <el-table-column prop="id" label="ID" min-width="80px"></el-table-column>
+        <el-table-column prop="name" label="绛夌骇鍚嶇О" min-width="120px"></el-table-column>
+        <el-table-column prop="detail" label="澶囨敞璇存槑" min-width="200px"></el-table-column>
+        <el-table-column prop="sortnum" label="鎺掑簭" min-width="100px"></el-table-column>
+        <el-table-column prop="createTime" label="鎻愪氦鏃堕棿" min-width="100px"></el-table-column>
+        <el-table-column label="鐘舵��" min-width="80px">
+          <template slot-scope="{row}">
+            <el-switch
+              @change="handleStatusChange($event, row)"
+              v-model="row.status"
+              active-color="#13ce66"
+              inactive-color="#ff4949"
+              :active-value="0"
+              :inactive-value="1"
+            ></el-switch>
+          </template>
+        </el-table-column>
+        <el-table-column label="鎿嶄綔" min-width="150" fixed="right">
+          <template slot-scope="{row}">
+            <el-button type="text" @click="handleEdit(row)">缂栬緫</el-button>
+            <el-button type="text" @click="deleteById(row.id)">鍒犻櫎</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <pagination
+        @size-change="handleSizeChange"
+        @current-change="handlePageChange"
+        :pagination="tableData.pagination"
+      ></pagination>
+    </template>
+    <OperaGoodsCategoryEditWindow ref="operaGoodsCategoryEditWindow" @success="search" />
+  </TableLayout>
+</template>
+
+<script>
+import BaseTable from '@/components/base/BaseTable'
+import TableLayout from '@/layouts/TableLayout'
+import Pagination from '@/components/common/Pagination'
+import OperaGoodsCategoryEditWindow from '@/components/business/OperaGoodsCategoryEditWindow'
+import { updateStatus } from '@/api/business/goodsCategory'
+
+export default {
+  name: 'ItemLevelList',
+  extends: BaseTable,
+  components: { TableLayout, Pagination, OperaGoodsCategoryEditWindow },
+  data () {
+    return {
+      searchForm: {
+        name: '',
+        type: 3
+      }
+    }
+  },
+  created () {
+    this.config({
+      api: '/business/goodsCategory',
+      'field.id': 'id'
+    })
+    this.search()
+  },
+  methods: {
+    handleEdit (row) {
+      this.$refs.operaGoodsCategoryEditWindow.open('缂栬緫鐗╁搧绛夌骇', row, 3)
+    },
+    handleStatusChange (val, row) {
+      updateStatus({ id: row.id, status: val }).then(res => {
+        this.$tip.apiSuccess(res || '淇敼鎴愬姛')
+      }).catch(e => {
+        row.status = val === 1 ? 0 : 1
+        this.$tip.apiFailed(e)
+      })
+    }
+  }
+}
+</script>
diff --git a/admin/src/views/business/memberList.vue b/admin/src/views/business/memberList.vue
new file mode 100644
index 0000000..ea79fa8
--- /dev/null
+++ b/admin/src/views/business/memberList.vue
@@ -0,0 +1,105 @@
+<template>
+  <TableLayout :permissions="['business:member:query']">
+    <el-form ref="searchForm" slot="search-form" :model="searchForm" label-width="100px" inline>
+      <el-form-item label="浼氬憳淇℃伅" prop="keyword">
+        <el-input v-model="searchForm.keyword" clearable placeholder="璇疯緭鍏ュ鍚�/鎵嬫満鍙�" @keypress.enter.native="search"></el-input>
+      </el-form-item>
+      <el-form-item label="鐘舵��" prop="status">
+        <el-select v-model="searchForm.status" clearable placeholder="璇烽�夋嫨鐘舵��" @change="search">
+          <el-option label="姝e父" :value="0"></el-option>
+          <el-option label="鍋滅敤" :value="1"></el-option>
+          <el-option label="宸叉敞閿�" :value="2"></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="鍒涘缓鏃堕棿" prop="createTime">
+        <el-date-picker type="daterange" v-model="searchForm.createTime" clearable value-format="yyyy-MM-dd"
+                        range-separator="-" start-placeholder="寮�濮嬫棩鏈�" end-placeholder="缁撴潫鏃ユ湡" @change="handleDateChange" />
+      </el-form-item>
+      <section>
+        <el-button type="primary" @click="search">鎼滅储</el-button>
+        <el-button @click="reset">閲嶇疆</el-button>
+        <el-button :loading="isWorking.export" @click="exportExcel">瀵煎嚭</el-button>
+      </section>
+    </el-form>
+    <template v-slot:table-wrap>
+      <el-table
+        :height="tableHeightNew"
+        v-loading="isWorking.search"
+        :data="tableData.list"
+        stripe
+      >
+        <el-table-column prop="nickName" label="鐢ㄦ埛鏄电О" min-width="120px"></el-table-column>
+        <el-table-column prop="name" label="浼氬憳濮撳悕" min-width="120px"></el-table-column>
+        <el-table-column prop="telephone" label="鎺堟潈鎵嬫満鍙�" min-width="130px"></el-table-column>
+        <el-table-column prop="createTime" label="鍒涘缓鏃堕棿" min-width="160px"></el-table-column>
+        <el-table-column label="鐘舵��" min-width="80px">
+          <template slot-scope="{row}">
+            {{ row.status === 0 ? '姝e父' : row.status === 1 ? '鍋滅敤' : '宸叉敞閿�' }}
+          </template>
+        </el-table-column>
+        <el-table-column label="鎿嶄綔" min-width="100" fixed="right">
+          <template slot-scope="{row}">
+            <el-button type="text" @click="handleDetail(row)">璇︽儏</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <pagination
+        @size-change="handleSizeChange"
+        @current-change="handlePageChange"
+        :pagination="tableData.pagination"
+      ></pagination>
+    </template>
+    <OperaMemberDetailWindow ref="operaMemberDetailWindow" />
+  </TableLayout>
+</template>
+
+<script>
+import BaseTable from '@/components/base/BaseTable'
+import TableLayout from '@/layouts/TableLayout'
+import Pagination from '@/components/common/Pagination'
+import OperaMemberDetailWindow from '@/components/business/OperaMemberDetail'
+
+export default {
+  name: 'MemberList',
+  extends: BaseTable,
+  components: { TableLayout, Pagination, OperaMemberDetailWindow },
+  data () {
+    return {
+      searchForm: {
+        keyword: '',
+        status: '',
+        createTime: '',
+        startTime: '',
+        endTime: ''
+      }
+    }
+  },
+  created () {
+    this.config({
+      api: '/business/memberManage',
+      'field.id': 'id'
+    })
+    this.search()
+  },
+  methods: {
+    handleDateChange (val) {
+      this.searchForm.startTime = val ? val[0] : ''
+      this.searchForm.endTime = val ? val[1] : ''
+      this.search()
+    },
+    reset () {
+      this.searchForm = {
+        keyword: '',
+        status: '',
+        createTime: '',
+        startTime: '',
+        endTime: ''
+      }
+      this.search()
+    },
+    handleDetail (row) {
+      this.$refs.operaMemberDetailWindow.open('浼氬憳璇︽儏', row)
+    }
+  }
+}
+</script>
diff --git a/admin/src/views/business/memberManage.vue b/admin/src/views/business/memberManage.vue
new file mode 100644
index 0000000..bcb2923
--- /dev/null
+++ b/admin/src/views/business/memberManage.vue
@@ -0,0 +1,149 @@
+<template>
+  <TableLayout :permissions="['business:member:query']">
+    <el-form ref="searchForm" slot="search-form" :model="searchForm" label-width="100px" inline>
+      <el-form-item label="浼氬憳淇℃伅" prop="keyword">
+        <el-input v-model="searchForm.keyword" clearable placeholder="璇疯緭鍏ョ敤鎴锋樀绉�/浼氬憳濮撳悕/鎵嬫満鍙�" @keypress.enter.native="search"></el-input>
+      </el-form-item>
+      <el-form-item label="鐘舵��" prop="status">
+        <el-select v-model="searchForm.status" clearable placeholder="璇烽�夋嫨鐘舵��" @change="search">
+          <el-option label="绂佺敤" :value="0"></el-option>
+          <el-option label="鍚敤" :value="1"></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="鍒涘缓鏃堕棿" prop="createTime">
+        <el-date-picker type="daterange" v-model="searchForm.createTime" clearable value-format="yyyy-MM-dd"
+                        range-separator="-" start-placeholder="寮�濮嬫棩鏈�" end-placeholder="缁撴潫鏃ユ湡" @change="handleDateChange" />
+      </el-form-item>
+      <section>
+        <el-button type="primary" @click="search">鎼滅储</el-button>
+        <el-button @click="reset">閲嶇疆</el-button>
+        <el-button :loading="isWorking.export" @click="handleExport">瀵煎嚭</el-button>
+      </section>
+    </el-form>
+    <template v-slot:table-wrap>
+      <el-table
+        :height="tableHeightNew"
+        v-loading="isWorking.search"
+        :data="tableData.list"
+        stripe
+      >
+        <el-table-column prop="nickName" label="鐢ㄦ埛鏄电О" min-width="120px"></el-table-column>
+        <el-table-column prop="name" label="浼氬憳濮撳悕" min-width="120px"></el-table-column>
+        <el-table-column prop="phone" label="鎺堟潈鎵嬫満鍙�" min-width="130px"></el-table-column>
+        <el-table-column prop="createTime" label="鍒涘缓鏃堕棿" min-width="160px"></el-table-column>
+        <el-table-column label="鐘舵��" min-width="80px">
+          <template slot-scope="{row}">
+            <el-switch
+              @change="handleStatusChange($event, row)"
+              v-model="row.status"
+              active-color="#13ce66"
+              inactive-color="#ff4949"
+              :active-value="1"
+              :inactive-value="0"
+            ></el-switch>
+          </template>
+        </el-table-column>
+        <el-table-column label="鎿嶄綔" min-width="100" fixed="right">
+          <template slot-scope="{row}">
+            <el-button type="text" @click="handleDetail(row)">璇︽儏</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <pagination
+        @size-change="handleSizeChange"
+        @current-change="handlePageChange"
+        :pagination="tableData.pagination"
+      ></pagination>
+    </template>
+    <OperaMemberDetail ref="operaMemberDetail" />
+  </TableLayout>
+</template>
+
+<script>
+import BaseTable from '@/components/base/BaseTable'
+import TableLayout from '@/layouts/TableLayout'
+import Pagination from '@/components/common/Pagination'
+import OperaMemberDetail from '@/components/business/OperaMemberDetail'
+import { fetchList, updateStatus, exportExcel } from '@/api/business/memberManage'
+
+export default {
+  name: 'MemberManage',
+  extends: BaseTable,
+  components: { TableLayout, Pagination, OperaMemberDetail },
+  data () {
+    return {
+      searchForm: {
+        keyword: '',
+        status: '',
+        createTime: '',
+        createStartTime: '',
+        createEndTime: ''
+      }
+    }
+  },
+  created () {
+    this.config({
+      api: '/business/member',
+      'field.id': 'id'
+    })
+    this.search()
+  },
+  methods: {
+    loadTableData (resolve) {
+      this.isWorking.search = true
+      fetchList(this.getTableParams())
+        .then(data => {
+          this.tableData.list = data.list || []
+          this.tableData.pagination.total = data.total || 0
+          if (resolve) resolve(data)
+        })
+        .catch(e => {
+          this.$tip.apiFailed(e, '鍔犺浇澶辫触')
+        })
+        .finally(() => {
+          this.isWorking.search = false
+        })
+    },
+    handleDateChange (val) {
+      this.searchForm.createStartTime = val ? val[0] : ''
+      this.searchForm.createEndTime = val ? val[1] : ''
+      this.search()
+    },
+    reset () {
+      this.searchForm = {
+        keyword: '',
+        status: '',
+        createTime: '',
+        createStartTime: '',
+        createEndTime: ''
+      }
+      this.search()
+    },
+    handleDetail (row) {
+      this.$refs.operaMemberDetail.open('浼氬憳璇︽儏', row)
+    },
+    handleStatusChange (val, row) {
+      updateStatus({ id: row.id, status: val }).then(res => {
+        this.$tip.apiSuccess(res || '淇敼鎴愬姛')
+      }).catch(e => {
+        row.status = val === 1 ? 0 : 1
+        this.$tip.apiFailed(e)
+      })
+    },
+    handleExport () {
+      this.isWorking.export = true
+      exportExcel(this.getTableParams())
+        .then(res => {
+          this.download(res)
+          this.$tip.apiSuccess('瀵煎嚭鎴愬姛')
+        })
+        .catch(e => {
+          this.$tip.apiFailed(e)
+        })
+        .finally(() => {
+          this.isWorking.export = false
+        })
+    }
+  }
+}
+</script>
diff --git a/admin/src/views/business/shopQualificationList.vue b/admin/src/views/business/shopQualificationList.vue
new file mode 100644
index 0000000..44c62c9
--- /dev/null
+++ b/admin/src/views/business/shopQualificationList.vue
@@ -0,0 +1,155 @@
+<template>
+  <TableLayout :permissions="['business:shopInfo:query']">
+    <el-form ref="searchForm" slot="search-form" :model="searchForm" label-width="100px" inline>
+      <el-form-item label="闂ㄥ簵鍚嶇О" prop="name">
+        <el-input v-model="searchForm.name" clearable placeholder="璇疯緭鍏ラ棬搴楀悕绉�" @keypress.enter.native="search"></el-input>
+      </el-form-item>
+      <el-form-item label="绫诲瀷" prop="companyType">
+        <el-select v-model="searchForm.companyType" clearable placeholder="璇烽�夋嫨绫诲瀷" @change="search">
+          <el-option label="浼佷笟" :value="1"></el-option>
+          <el-option label="涓汉" :value="0"></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="闂ㄥ簵鍦板潃" prop="address">
+        <el-input v-model="searchForm.address" clearable placeholder="璇疯緭鍏ラ棬搴楀湴鍧�" @keypress.enter.native="search"></el-input>
+      </el-form-item>
+      <el-form-item label="鑱旂郴浜�" prop="linkName">
+        <el-input v-model="searchForm.linkName" clearable placeholder="璇疯緭鍏ヨ仈绯讳汉" @keypress.enter.native="search"></el-input>
+      </el-form-item>
+      <el-form-item label="鑱旂郴鐢佃瘽" prop="linkPhone">
+        <el-input v-model="searchForm.linkPhone" clearable placeholder="璇疯緭鍏ヨ仈绯荤數璇�" @keypress.enter.native="search"></el-input>
+      </el-form-item>
+      <el-form-item label="鎻愪氦鏃堕棿" prop="createTime">
+        <el-date-picker type="daterange" v-model="searchForm.createTime" clearable value-format="yyyy-MM-dd"
+                        range-separator="-" start-placeholder="寮�濮嬫棩鏈�" end-placeholder="缁撴潫鏃ユ湡" @change="handleDateChange" />
+      </el-form-item>
+      <el-form-item label="鐘舵��" prop="auditStatus">
+        <el-select v-model="searchForm.auditStatus" clearable placeholder="璇烽�夋嫨鐘舵��" @change="search">
+          <el-option label="寰呭鎵�" :value="0"></el-option>
+          <el-option label="瀹℃壒閫氳繃" :value="1"></el-option>
+          <el-option label="瀹℃壒鏈�氳繃" :value="2"></el-option>
+        </el-select>
+      </el-form-item>
+      <section>
+        <el-button type="primary" @click="search">鎼滅储</el-button>
+        <el-button @click="reset">閲嶇疆</el-button>
+      </section>
+    </el-form>
+    <template v-slot:table-wrap>
+      <el-table
+          :height="tableHeightNew"
+        v-loading="isWorking.search"
+        :data="tableData.list"
+        stripe
+        @selection-change="handleSelectionChange"
+      >
+        <el-table-column type="selection" width="55"></el-table-column>
+        <el-table-column prop="name" label="闂ㄥ簵鍚嶇О" min-width="120px">
+          <template slot-scope="{row}">
+            <span class="link-name" @click="openShopInfo(row)">{{ row.name }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="companyType" label="绫诲瀷" min-width="80px">
+          <template slot-scope="{row}">
+            {{row.companyType == 1 ? '浼佷笟' : '涓汉'}}
+          </template>
+        </el-table-column>
+        <el-table-column prop="address" label="闂ㄥ簵鍦板潃" min-width="200px"></el-table-column>
+        <el-table-column prop="linkName" label="鑱旂郴浜�" min-width="100px"></el-table-column>
+        <el-table-column prop="linkPhone" label="鑱旂郴鐢佃瘽" min-width="120px"></el-table-column>
+        <el-table-column prop="createTime" label="鎻愪氦鏃ユ湡" min-width="160px"></el-table-column>
+        <el-table-column label="瀹℃壒鐘舵��" min-width="100px">
+          <template slot-scope="{row}">
+            <span style="color: yellow;" v-if="row.auditStatus == 0">寰呭鎵�</span>
+            <span style="color: #13ce66;" v-else-if="row.auditStatus == 1">瀹℃壒閫氳繃</span>
+            <span style="color: #ff4949;" v-else-if="row.auditStatus == 2">瀹℃壒鏈�氳繃</span>
+            <span style="color: #13ce66;" v-else-if="row.auditStatus == 3">宸叉敮浠樻娂閲�</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="鎿嶄綔" min-width="150" fixed="right">
+          <template slot-scope="{row}">
+            <el-button type="text" v-if="row.auditStatus == 0" @click="handleAudit(row)">瀹℃牳</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <pagination
+        @size-change="handleSizeChange"
+        @current-change="handlePageChange"
+        :pagination="tableData.pagination"
+      >
+      </pagination>
+    </template>
+    <!-- 闂ㄥ簵璇︽儏 -->
+    <OperaShopInfoSeeWindow ref="operaShopInfoSeeWindow" />
+    <OperaShopApprovalWindow ref="operaShopApprovalWindow" @success="search" />
+  </TableLayout>
+</template>
+
+<script>
+import BaseTable from '@/components/base/BaseTable'
+import TableLayout from '@/layouts/TableLayout'
+import Pagination from '@/components/common/Pagination'
+import OperaShopInfoSeeWindow from '@/components/business/OperaShopInfoSeeWindow'
+import OperaShopApprovalWindow from '@/components/business/OperaShopApprovalWindow'
+
+export default {
+  name: 'ShopQualificationList',
+  extends: BaseTable,
+  components: { TableLayout, Pagination, OperaShopInfoSeeWindow, OperaShopApprovalWindow },
+  data () {
+    return {
+      searchForm: {
+        name: '',
+        companyType: '',
+        address: '',
+        linkName: '',
+        linkPhone: '',
+        createTime: '',
+        createStartTime: '',
+        createEndTime: '',
+        auditStatusList: [0,1,2]
+      }
+    }
+  },
+  created () {
+    this.config({
+      module: '闂ㄥ簵鍒楄〃',
+      api: '/business/shopInfo',
+      'field.id': 'id',
+      'field.main': 'id'
+    })
+    this.search()
+  },
+  methods: {
+    reset () {
+      this.searchForm = {
+        name: '',
+        companyType: '',
+        address: '',
+        linkName: '',
+        linkPhone: '',
+        createTime: '',
+        status: ''
+      }
+      this.search()
+    },
+    handleDateChange (val) {
+      this.searchForm.createStartTime = val ? val[0] : ''
+      this.searchForm.createEndTime = val ? val[1] : ''
+    },
+    handleAudit (row) {
+      this.$refs.operaShopApprovalWindow.open('闂ㄥ簵瀹℃壒', row)
+    },
+    openShopInfo (row) {
+      this.$refs.operaShopInfoSeeWindow.open('闂ㄥ簵淇℃伅', row)
+    }
+  }
+}
+</script>
+<style scoped>
+.link-name {
+  color: #2E68EC;
+  text-decoration: underline;
+  cursor: pointer;
+}
+</style>
\ No newline at end of file
diff --git a/admin/src/views/business/shopWithdrawList.vue b/admin/src/views/business/shopWithdrawList.vue
new file mode 100644
index 0000000..da28849
--- /dev/null
+++ b/admin/src/views/business/shopWithdrawList.vue
@@ -0,0 +1,156 @@
+<template>
+  <TableLayout :permissions="['business:withdrawalorders:query']">
+    <el-form ref="searchForm" slot="search-form" :model="searchForm" label-width="100px" inline>
+      <el-form-item label="闂ㄥ簵鍚嶇О" prop="shopName">
+        <el-input v-model="searchForm.shopName" clearable placeholder="璇疯緭鍏ラ棬搴楀悕绉�" @keypress.enter.native="search"></el-input>
+      </el-form-item>
+      <el-form-item label="鐢宠鏃堕棿" prop="createTime1">
+        <el-date-picker type="daterange" v-model="searchForm.createTime1" clearable value-format="yyyy-MM-dd"
+                        range-separator="-" start-placeholder="寮�濮嬫棩鏈�" end-placeholder="缁撴潫鏃ユ湡" @change="handleDateChange" />
+      </el-form-item>
+      <el-form-item label="瀹℃壒鐘舵��" prop="status">
+        <el-select v-model="searchForm.status" clearable placeholder="璇烽�夋嫨鐘舵��" @change="search">
+          <el-option label="鎻愮幇鐢宠涓�" :value="0"></el-option>
+          <el-option label="鎻愮幇鎴愬姛" :value="1"></el-option>
+          <el-option label="鎻愮幇澶辫触" :value="2"></el-option>
+        </el-select>
+      </el-form-item>
+      <section>
+        <el-button type="primary" @click="search">鎼滅储</el-button>
+        <el-button @click="reset">閲嶇疆</el-button>
+      </section>
+    </el-form>
+    <template v-slot:table-wrap>
+      <div class="total-amount">
+        <span>绱鎻愮幇锛毬{ totalAmount }}</span>
+      </div>
+      <el-table
+        :height="tableHeightNew"
+        v-loading="isWorking.search"
+        :data="tableData.list"
+        stripe
+      >
+        <el-table-column prop="shopName" label="闂ㄥ簵鍚嶇О" min-width="120px"></el-table-column>
+        <el-table-column prop="linkName" label="闂ㄥ簵鑱旂郴浜�" min-width="100px"></el-table-column>
+        <el-table-column prop="amount" label="鎻愮幇閲戦锛堝厓锛�" min-width="120px">
+          <template slot-scope="{row}">
+            <span class="amount">楼{{ row.amount / 100 }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="createTime" label="鐢宠鏃堕棿" min-width="160px"></el-table-column>
+        <el-table-column label="瀹℃牳鐘舵��" min-width="100px">
+          <template slot-scope="{row}">
+            <span :style="{ color: getStatusColor(row.status) }">
+              {{ getStatusText(row.status) }}
+            </span>
+          </template>
+        </el-table-column>
+        <el-table-column label="鎿嶄綔" min-width="100" fixed="right">
+          <template slot-scope="{row}">
+            <el-button type="text" @click="handleView(row)">鏌ョ湅</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <pagination
+        @size-change="handleSizeChange"
+        @current-change="handlePageChange"
+        :pagination="tableData.pagination"
+      ></pagination>
+    </template>
+    <OperaWithdrawDetailWindow ref="operaWithdrawDetailWindow" @success="search" />
+  </TableLayout>
+</template>
+
+<script>
+import BaseTable from '@/components/base/BaseTable'
+import TableLayout from '@/layouts/TableLayout'
+import Pagination from '@/components/common/Pagination'
+import OperaWithdrawDetailWindow from '@/components/business/OperaWithdrawDetailWindow'
+import { fetchList, getTotalAmount } from '@/api/business/shopWithdraw'
+
+export default {
+  name: 'ShopWithdrawList',
+  extends: BaseTable,
+  components: { TableLayout, Pagination, OperaWithdrawDetailWindow },
+  data () {
+    return {
+      totalAmount: '0.00',
+      searchForm: {
+        shopName: '',
+        createTime1: '',
+        createStartTime: '',
+        createEndTime: '',
+        status: ''
+      }
+    }
+  },
+  created () {
+    this.config({
+      api: '/business/shopWithdraw',
+      'field.id': 'id'
+    })
+    this.loadTotalAmount()
+    this.search()
+  },
+  methods: {
+    loadTotalAmount () {
+      getTotalAmount({
+        capacity: 99999,
+        pageNum: 1,
+        model: {
+          shopName: this.searchForm.shopName,
+          createStartTime: this.searchForm.createStartTime,
+          createEndTime: this.searchForm.createEndTime,
+          status: this.searchForm.status
+        }
+      }).then(res => {
+        this.totalAmount = res / 100 || '0.00'
+      }).catch(e => {
+        this.$tip.apiFailed(e)
+      })
+    },
+    getStatusText (status) {
+      const map = { 0: '鎻愮幇鐢宠涓�', 1: '鎻愮幇鎴愬姛', 2: '鎻愮幇澶辫触' }
+      return map[status] || '-'
+    },
+    getStatusColor (status) {
+      const map = { 0: '#E6A23C', 1: '#67C23A', 2: '#F56C6C' }
+      return map[status] || '#606266'
+    },
+    handleDateChange (val) {
+      this.searchForm.createStartTime = val ? val[0] : ''
+      this.searchForm.createEndTime = val ? val[1] : ''
+      this.search()
+    },
+    reset () {
+      this.searchForm = {
+        shopName: '',
+        createTime1: '',
+        createStartTime: '',
+        createEndTime: '',
+        auditStatus: ''
+      }
+      this.search()
+    },
+    handleView (row) {
+      this.$refs.operaWithdrawDetailWindow.open('鎻愮幇璇︽儏', row)
+    }
+  }
+}
+</script>
+
+<style scoped>
+.total-amount {
+  padding: 15px 20px;
+  background: #f5f7fa;
+  border-radius: 8px;
+  margin-bottom: 15px;
+  font-size: 16px;
+  font-weight: bold;
+  color: #303133;
+}
+.amount {
+  color: #f56c6c;
+  font-weight: bold;
+}
+</style>
diff --git a/admin/src/views/business/storeList.vue b/admin/src/views/business/storeList.vue
index 5d5dd4e..f60485d 100644
--- a/admin/src/views/business/storeList.vue
+++ b/admin/src/views/business/storeList.vue
@@ -108,7 +108,7 @@
         createTime: '',
         createStartTime: '',
         createEndTime: '',
-        auditStatus: ''
+        auditStatus: 3
       }
     }
   },
@@ -130,7 +130,8 @@
         linkName: '',
         linkPhone: '',
         createTime: '',
-        status: ''
+        status: '',
+        auditStatus: 3
       }
       this.search()
     },
diff --git a/admin/src/views/business/sysParams.vue b/admin/src/views/business/sysParams.vue
new file mode 100644
index 0000000..4d975db
--- /dev/null
+++ b/admin/src/views/business/sysParams.vue
@@ -0,0 +1,162 @@
+<template>
+  <TableLayout>
+    <template v-slot:table-wrap>
+      <div class="params-container">
+      <div class="section">
+        <h3 class="section-title">鍙告満瑙勫垯</h3>
+        <div class="form-item">
+          <span class="label">鍙告満姣忔棩鍙彇娑堣鍗曟鏁颁负</span>
+          <el-input-number v-model="form.driverDailyCancelLimit" :min="0" controls-position="right"></el-input-number>
+          <span class="desc">娆★紝瓒呰繃娆℃暟鍚庯紝浠婃棩涓嶅彲鎶㈠崟</span>
+        </div>
+        <div class="form-item">
+          <span class="label">鍙告満鏈�澶у悓鏃惰繘琛屼腑璁㈠崟鏁伴噺涓�</span>
+          <el-input-number v-model="form.orderAcceptLimit" :min="0" controls-position="right"></el-input-number>
+          <span class="desc">涓紝瓒呰繃璇ユ暟閲忎笉鍏佽鎶㈠崟<span class="red">锛堝嵆璁㈠崟鐘舵��=寰呭彇浠�/閰嶉�佷腑锛�</span></span>
+        </div>
+      </div>
+
+      <div class="section">
+        <h3 class="section-title">璁㈠崟瑙勫垯</h3>
+        <div class="form-item">
+          <span class="label">瓒呮椂</span>
+          <el-input-number v-model="form.autoCancelTime" :min="0" controls-position="right"></el-input-number>
+          <span class="desc">鍒嗛挓鏈敮浠橈紝璁㈠崟鑷姩鍙栨秷</span>
+        </div>
+        <div class="form-item">
+          <span class="label">鎬ラ�熻揪璁㈠崟璁′环绯绘暟</span>
+          <el-input-number v-model="form.urgentCoefficient" :min="0" :precision="2" controls-position="right"></el-input-number>
+        </div>
+        <div class="form-item">
+          <span class="label">鐗╁搧淇濊垂姣斾緥</span>
+          <el-input-number v-model="form.insuranceRate" :min="0" :precision="2" controls-position="right"></el-input-number>
+          <span class="desc">%</span>
+        </div>
+        <div class="form-item">
+          <span class="label">寮傚湴瀵勯�佹ā寮忎笅锛岃嫢鐗╁搧宸查�佽揪锛岃�屽鎴峰綋澶╂湭鍙栦欢锛屽垯鍚庣画绯荤粺鎸�</span>
+          <el-input-number v-model="form.unpickedDiscount" :min="0" :precision="2" controls-position="right"></el-input-number>
+          <span class="desc">鎶樻墸绯绘暟璁$畻</span>
+        </div>
+        <div class="form-item">
+          <span class="label">璁㈠崟閫佽揪鍚庨粯璁�</span>
+          <el-input-number v-model="form.autoConfirmReceipt" :min="0" controls-position="right"></el-input-number>
+          <span class="desc">澶╁悗鑷姩纭鏀惰揣<span class="red">锛堜粎闄愭敹浠跺湴鍧�涓嶆槸鏈嶅姟鐐圭殑鎯呭喌锛�</span></span>
+        </div>
+        <div class="form-item">
+          <span class="label">璁㈠崟瀹屾垚鍚�</span>
+          <el-input-number v-model="form.settlementDate" :min="0" controls-position="right"></el-input-number>
+          <span class="desc">澶╁悗绯荤粺缁撶畻璁㈠崟锛屽苟缁欎笌鍙備笌瑙掕壊鎸夋瘮渚嬪垎鎴�</span>
+        </div>
+      </div>
+
+      <div class="footer">
+        <el-button type="primary" @click="handleSave" :loading="isWorking.save">淇濆瓨</el-button>
+      </div>
+    </div>
+    </template>
+  </TableLayout>
+</template>
+
+<script>
+import TableLayout from '@/layouts/TableLayout'
+import { getParams, saveParams } from '@/api/business/sysParams'
+
+export default {
+  name: 'SysParams',
+  components: { TableLayout },
+  data () {
+    return {
+      form: {
+        autoCancelTime: '',
+        autoConfirmReceipt: '',
+        driverDailyCancelLimit: '',
+        insuranceRate: '',
+        orderAcceptLimit: '',
+        settlementDate: '',
+        unpickedDiscount: '',
+        urgentCoefficient: ''
+      },
+      isWorking: {
+        save: false
+      }
+    }
+  },
+  created () {
+    this.loadData()
+  },
+  methods: {
+    loadData () {
+      getParams().then(res => {
+        this.form = {
+          autoCancelTime: res.autoCancelTime || '',
+          autoConfirmReceipt: res.autoConfirmReceipt || '',
+          driverDailyCancelLimit: res.driverDailyCancelLimit || '',
+          insuranceRate: res.insuranceRate || '',
+          orderAcceptLimit: res.orderAcceptLimit || '',
+          settlementDate: res.settlementDate || '',
+          unpickedDiscount: res.unpickedDiscount || '',
+          urgentCoefficient: res.urgentCoefficient || ''
+        }
+      }).catch(e => {
+        this.$tip.apiFailed(e)
+      })
+    },
+    handleSave () {
+      this.isWorking.save = true
+      saveParams(this.form).then(res => {
+        this.$tip.apiSuccess(res || '淇濆瓨鎴愬姛')
+      }).catch(e => {
+        this.$tip.apiFailed(e)
+      }).finally(() => {
+        this.isWorking.save = false
+      })
+    }
+  }
+}
+</script>
+
+<style scoped>
+.params-container {
+  padding: 20px;
+}
+.section {
+  margin-bottom: 40px;
+}
+.section-title {
+  font-size: 16px;
+  font-weight: bold;
+  color: #303133;
+  margin-bottom: 20px;
+  padding-left: 10px;
+  border-left: 4px solid #2E68EC;
+}
+.form-item {
+  display: flex;
+  align-items: center;
+  margin-bottom: 20px;
+  flex-wrap: wrap;
+}
+.form-item .label {
+  color: #606266;
+  font-size: 14px;
+  white-space: nowrap;
+}
+.form-item .desc {
+  color: #909399;
+  font-size: 14px;
+  margin-left: 10px;
+}
+.form-item .red {
+  color: #f56c6c;
+}
+.form-item /deep/ .el-input-number {
+  margin: 0 10px;
+}
+.form-item /deep/ .el-input-number .el-input__inner {
+  text-align: center;
+}
+.footer {
+  padding-top: 20px;
+  border-top: 1px solid #eee;
+}
+</style>
diff --git a/admin/src/views/business/vehicleType.vue b/admin/src/views/business/vehicleType.vue
new file mode 100644
index 0000000..c28dab4
--- /dev/null
+++ b/admin/src/views/business/vehicleType.vue
@@ -0,0 +1,99 @@
+<template>
+  <TableLayout :permissions="['business:category:query']">
+    <el-form ref="searchForm" slot="search-form" :model="searchForm" label-width="100px" inline>
+      <el-form-item label="鍚嶇О" prop="name">
+        <el-input v-model="searchForm.name" clearable placeholder="璇疯緭鍏ュ悕绉�" @keypress.enter.native="search"></el-input>
+      </el-form-item>
+      <section>
+        <el-button type="primary" @click="search">鎼滅储</el-button>
+        <el-button @click="reset">閲嶇疆</el-button>
+      </section>
+    </el-form>
+    <template v-slot:table-wrap>
+      <ul class="toolbar">
+        <li><el-button type="primary" @click="$refs.operaGoodsCategoryEditWindow.open('鏂板缓鐗╁搧绛夌骇', null, 1)" icon="el-icon-plus">鏂板缓</el-button></li>
+      </ul>
+      <el-table
+        :height="tableHeightNew"
+        v-loading="isWorking.search"
+        :data="tableData.list"
+        stripe
+      >
+        <el-table-column prop="id" label="ID" min-width="80px"></el-table-column>
+        <el-table-column prop="name" label="绫诲瀷鍚嶇О" min-width="120px"></el-table-column>
+        <el-table-column prop="detail" label="閫氳鏂瑰紡" min-width="200px">
+          <template slot-scope="{row}">
+            {{ row.otherField === 'driving' ? '鏈哄姩杞�' : '闈炴満鍔ㄨ溅' }}
+          </template>
+        </el-table-column>
+        <el-table-column prop="sortnum" label="鍒嗙被鎺掑簭" min-width="100px"></el-table-column>
+        <el-table-column label="鐘舵��" min-width="80px">
+          <template slot-scope="{row}">
+            <el-switch
+              @change="handleStatusChange($event, row)"
+              v-model="row.status"
+              active-color="#13ce66"
+              inactive-color="#ff4949"
+              :active-value="0"
+              :inactive-value="1"
+            ></el-switch>
+          </template>
+        </el-table-column>
+        <el-table-column label="鎿嶄綔" min-width="150" fixed="right">
+          <template slot-scope="{row}">
+            <el-button type="text" @click="handleEdit(row)">缂栬緫</el-button>
+            <el-button type="text" @click="deleteById(row.id)">鍒犻櫎</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <pagination
+        @size-change="handleSizeChange"
+        @current-change="handlePageChange"
+        :pagination="tableData.pagination"
+      ></pagination>
+    </template>
+    <OperaGoodsCategoryEditWindow ref="operaGoodsCategoryEditWindow" @success="search" />
+  </TableLayout>
+</template>
+
+<script>
+import BaseTable from '@/components/base/BaseTable'
+import TableLayout from '@/layouts/TableLayout'
+import Pagination from '@/components/common/Pagination'
+import OperaGoodsCategoryEditWindow from '@/components/business/OperaGoodsCategoryEditWindow'
+import { updateStatus } from '@/api/business/goodsCategory'
+
+export default {
+  name: 'VehicleType',
+  extends: BaseTable,
+  components: { TableLayout, Pagination, OperaGoodsCategoryEditWindow },
+  data () {
+    return {
+      searchForm: {
+        name: '',
+        type: 1
+      }
+    }
+  },
+  created () {
+    this.config({
+      api: '/business/goodsCategory',
+      'field.id': 'id'
+    })
+    this.search()
+  },
+  methods: {
+    handleEdit (row) {
+      this.$refs.operaGoodsCategoryEditWindow.open('缂栬緫鐗╁搧绛夌骇', row, 1)
+    },
+    handleStatusChange (val, row) {
+      updateStatus({ id: row.id, status: val }).then(res => {
+        this.$tip.apiSuccess(res || '淇敼鎴愬姛')
+      }).catch(e => {
+        row.status = val === 1 ? 0 : 1
+        this.$tip.apiFailed(e)
+      })
+    }
+  }
+}
+</script>

--
Gitblit v1.9.3