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