系统管理后台实现商户页面和用户页面
This commit is contained in:
10
src/api/feedback.js
Normal file
10
src/api/feedback.js
Normal file
@ -0,0 +1,10 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 获取用户列表
|
||||
export function feedbackList(params) {
|
||||
return request({
|
||||
url: '/x/feedback',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
18
src/api/merchant.js
Normal file
18
src/api/merchant.js
Normal file
@ -0,0 +1,18 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
|
||||
export function merchantList(params){
|
||||
return request({
|
||||
url: '/x/merchant',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
export function merchantAudit(data) {
|
||||
return request({
|
||||
url: '/x/merchant/audit',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
36
src/api/user.js
Normal file
36
src/api/user.js
Normal file
@ -0,0 +1,36 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 获取用户列表
|
||||
export function userList(params) {
|
||||
return request({
|
||||
url: '/x/user/list',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 删除用户
|
||||
export function deleteUser(id) {
|
||||
return request({
|
||||
url: `/api/users/${id}`,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 批量删除用户
|
||||
export function batchDeleteUsers(ids) {
|
||||
return request({
|
||||
url: '/api/users/batch',
|
||||
method: 'delete',
|
||||
data: { ids }
|
||||
})
|
||||
}
|
||||
|
||||
// 更新用户状态
|
||||
export function updateUserStatus(id, status) {
|
||||
return request({
|
||||
url: `/api/users/${id}/status`,
|
||||
method: 'put',
|
||||
data: { status }
|
||||
})
|
||||
}
|
||||
186
src/views/merchant/components/approved.vue
Normal file
186
src/views/merchant/components/approved.vue
Normal file
@ -0,0 +1,186 @@
|
||||
<template>
|
||||
<div class="approved-list">
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
:data="tableData"
|
||||
border={false}
|
||||
class="custom-table"
|
||||
header-row-class-name="custom-header"
|
||||
row-class-name="custom-row"
|
||||
>
|
||||
<el-table-column prop="name" label="商户名称" header-align="center" align="center" />
|
||||
<el-table-column prop="contactName" label="联系人" header-align="center" align="center" />
|
||||
<el-table-column prop="contactPhone" label="联系电话" header-align="center" align="center" />
|
||||
<el-table-column prop="contactEmail" label="联系邮箱" header-align="center" align="center" />
|
||||
<el-table-column prop="address" label="地址" header-align="center" align="center" />
|
||||
<el-table-column prop="auditAt" label="通过时间" header-align="center" align="center" />
|
||||
<el-table-column prop="expireAt" label="服务到期时间" header-align="center" align="center" />
|
||||
<el-table-column prop="status" label="状态" header-align="center" align="center">
|
||||
<template slot-scope="scope">
|
||||
<span :class="['status-tag', scope.row.status === 1 ? 'status-normal' : 'status-block']">
|
||||
{{ scope.row.status === 1 ? '正常' : '禁用' }}
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="280" header-align="center" align="center">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="text" size="mini" class="edit-btn" @click="handleEdit(scope.row)">编辑</el-button>
|
||||
<el-button type="text" size="mini" class="view-btn" @click="handleViewStores(scope.row)">查看门店</el-button>
|
||||
<el-button
|
||||
type="text"
|
||||
size="mini"
|
||||
:class="scope.row.status === 1 ? 'block-btn' : 'unblock-btn'"
|
||||
@click="handleToggleStatus(scope.row)"
|
||||
>
|
||||
{{ scope.row.status === 1 ? '禁用' : '启用' }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 编辑弹窗 -->
|
||||
<merchant-edit
|
||||
:visible.sync="editDialogVisible"
|
||||
:merchant-data="currentMerchant"
|
||||
@success="handleEditSuccess"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { merchantList } from '@/api/merchant'
|
||||
import MerchantEdit from './merchant-edit.vue'
|
||||
|
||||
export default {
|
||||
name: 'ApprovedList',
|
||||
components: {
|
||||
MerchantEdit
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
tableData: [],
|
||||
editDialogVisible: false,
|
||||
currentMerchant: {}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getList()
|
||||
},
|
||||
methods: {
|
||||
async getList() {
|
||||
try {
|
||||
this.loading = true
|
||||
const res = await merchantList({
|
||||
auditStatus: 2
|
||||
})
|
||||
if (res.code === 0) {
|
||||
this.tableData = res.data.list || []
|
||||
} else {
|
||||
this.$message.error(res.message || '获取已通过列表失败')
|
||||
}
|
||||
} catch (error) {
|
||||
this.$message.error('获取已通过列表失败')
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
handleEdit(row) {
|
||||
this.currentMerchant = { ...row }
|
||||
this.editDialogVisible = true
|
||||
},
|
||||
handleViewStores(row) {
|
||||
// TODO: 实现查看门店功能
|
||||
this.$message.info('查看门店功能开发中')
|
||||
},
|
||||
async handleToggleStatus(row) {
|
||||
try {
|
||||
const action = row.status === 1 ? '禁用' : '启用'
|
||||
await this.$confirm(`确认${action}该商户吗?`, '提示', {
|
||||
type: 'warning'
|
||||
})
|
||||
// TODO: 调用禁用/启用接口
|
||||
this.$message.success(`${action}成功`)
|
||||
this.getList()
|
||||
} catch (error) {
|
||||
if (error !== 'cancel') {
|
||||
this.$message.error('操作失败')
|
||||
}
|
||||
}
|
||||
},
|
||||
handleEditSuccess() {
|
||||
this.getList()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.approved-list {
|
||||
margin-top: 20px;
|
||||
}
|
||||
.custom-table {
|
||||
background: #fff;
|
||||
border: none;
|
||||
font-size: 15px;
|
||||
::v-deep .el-table__body-wrapper td,
|
||||
::v-deep .el-table__header-wrapper th {
|
||||
border-right: none !important;
|
||||
border-left: none !important;
|
||||
}
|
||||
}
|
||||
.custom-header th {
|
||||
background: #f7f8fa !important;
|
||||
color: #888;
|
||||
font-weight: 500;
|
||||
border-bottom: 1px solid #f0f0f0 !important;
|
||||
border-top: 1px solid #f0f0f0 !important;
|
||||
padding-top: 16px !important;
|
||||
padding-bottom: 16px !important;
|
||||
height: 56px !important;
|
||||
line-height: 24px !important;
|
||||
}
|
||||
.custom-row td {
|
||||
border-bottom: 1px solid #f0f0f0 !important;
|
||||
border-top: none !important;
|
||||
padding-top: 14px !important;
|
||||
padding-bottom: 14px !important;
|
||||
height: 52px !important;
|
||||
line-height: 22px !important;
|
||||
vertical-align: middle !important;
|
||||
}
|
||||
.status-tag {
|
||||
display: inline-block;
|
||||
padding: 2px 16px;
|
||||
border-radius: 16px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
}
|
||||
.status-normal {
|
||||
background: #e8f7ea;
|
||||
color: #3fc06d;
|
||||
}
|
||||
.status-block {
|
||||
background: #fbeaea;
|
||||
color: #f56c6c;
|
||||
}
|
||||
.edit-btn {
|
||||
color: #556ff6;
|
||||
font-weight: 500;
|
||||
}
|
||||
.view-btn {
|
||||
color: #67c23a;
|
||||
font-weight: 500;
|
||||
margin-left: 8px;
|
||||
}
|
||||
.block-btn {
|
||||
color: #f56c6c;
|
||||
font-weight: 500;
|
||||
margin-left: 8px;
|
||||
}
|
||||
.unblock-btn {
|
||||
color: #67c23a;
|
||||
font-weight: 500;
|
||||
margin-left: 8px;
|
||||
}
|
||||
</style>
|
||||
179
src/views/merchant/components/merchant-edit.vue
Normal file
179
src/views/merchant/components/merchant-edit.vue
Normal file
@ -0,0 +1,179 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
:title="isEdit ? '编辑商户' : '新增商户'"
|
||||
:visible.sync="dialogVisible"
|
||||
width="600px"
|
||||
:close-on-click-modal="false"
|
||||
@close="handleClose"
|
||||
>
|
||||
<el-form
|
||||
ref="form"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
label-width="100px"
|
||||
class="merchant-form"
|
||||
>
|
||||
<el-form-item label="商户名称" prop="name">
|
||||
<el-input v-model="form.name" placeholder="请输入商户名称" />
|
||||
</el-form-item>
|
||||
<el-form-item label="联系人" prop="contactName">
|
||||
<el-input v-model="form.contactName" placeholder="请输入联系人" />
|
||||
</el-form-item>
|
||||
<el-form-item label="联系电话" prop="contactPhone">
|
||||
<el-input v-model="form.contactPhone" placeholder="请输入联系电话" />
|
||||
</el-form-item>
|
||||
<el-form-item label="联系邮箱" prop="contactEmail">
|
||||
<el-input v-model="form.contactEmail" placeholder="请输入联系邮箱" />
|
||||
</el-form-item>
|
||||
<el-form-item label="地址" prop="address">
|
||||
<el-input v-model="form.address" placeholder="请输入地址" />
|
||||
</el-form-item>
|
||||
<el-form-item label="服务到期时间" prop="expireAt" v-if="isEdit">
|
||||
<el-date-picker
|
||||
v-model="form.expireAt"
|
||||
type="datetime"
|
||||
placeholder="请选择服务到期时间"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="status" v-if="isEdit">
|
||||
<el-radio-group v-model="form.status">
|
||||
<el-radio :label="1">正常</el-radio>
|
||||
<el-radio :label="2">禁用</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="handleClose">取 消</el-button>
|
||||
<el-button type="primary" :loading="loading" @click="handleSubmit">确 定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { merchantUpdate, merchantCreate } from '@/api/merchant'
|
||||
|
||||
export default {
|
||||
name: 'MerchantEdit',
|
||||
props: {
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
merchantData: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dialogVisible: false,
|
||||
loading: false,
|
||||
isEdit: false,
|
||||
form: {
|
||||
name: '',
|
||||
contactName: '',
|
||||
contactPhone: '',
|
||||
contactEmail: '',
|
||||
address: '',
|
||||
expireAt: '',
|
||||
status: 1
|
||||
},
|
||||
rules: {
|
||||
name: [
|
||||
{ required: true, message: '请输入商户名称', trigger: 'blur' },
|
||||
{ min: 2, max: 50, message: '长度在 2 到 50 个字符', trigger: 'blur' }
|
||||
],
|
||||
contactName: [
|
||||
{ required: true, message: '请输入联系人', trigger: 'blur' }
|
||||
],
|
||||
contactPhone: [
|
||||
{ required: true, message: '请输入联系电话', trigger: 'blur' },
|
||||
{ pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号码', trigger: 'blur' }
|
||||
],
|
||||
contactEmail: [
|
||||
{ required: true, message: '请输入联系邮箱', trigger: 'blur' },
|
||||
{ type: 'email', message: '请输入正确的邮箱地址', trigger: 'blur' }
|
||||
],
|
||||
address: [
|
||||
{ required: true, message: '请输入地址', trigger: 'blur' }
|
||||
],
|
||||
expireAt: [
|
||||
{ required: true, message: '请选择服务到期时间', trigger: 'change' }
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
visible(val) {
|
||||
this.dialogVisible = val
|
||||
if (val) {
|
||||
this.initForm()
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
initForm() {
|
||||
this.isEdit = !!this.merchantData.id
|
||||
if (this.isEdit) {
|
||||
this.form = { ...this.merchantData }
|
||||
} else {
|
||||
this.form = {
|
||||
name: '',
|
||||
contactName: '',
|
||||
contactPhone: '',
|
||||
contactEmail: '',
|
||||
address: '',
|
||||
expireAt: '',
|
||||
status: 1
|
||||
}
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
this.$refs.form && this.$refs.form.clearValidate()
|
||||
})
|
||||
},
|
||||
handleClose() {
|
||||
this.$emit('update:visible', false)
|
||||
},
|
||||
async handleSubmit() {
|
||||
try {
|
||||
await this.$refs.form.validate()
|
||||
this.loading = true
|
||||
const api = this.isEdit ? merchantUpdate : merchantCreate
|
||||
const res = await api(this.form)
|
||||
if (res.code === 0) {
|
||||
this.$message.success(this.isEdit ? '编辑成功' : '新增成功')
|
||||
this.$emit('success')
|
||||
this.handleClose()
|
||||
} else {
|
||||
this.$message.error(res.message || '操作失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.merchant-form {
|
||||
padding: 20px 0;
|
||||
::v-deep .el-form-item__label {
|
||||
font-weight: 500;
|
||||
}
|
||||
::v-deep .el-input__inner {
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
}
|
||||
::v-deep .el-date-editor.el-input {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
.dialog-footer {
|
||||
text-align: right;
|
||||
padding-top: 20px;
|
||||
}
|
||||
</style>
|
||||
177
src/views/merchant/components/pending.vue
Normal file
177
src/views/merchant/components/pending.vue
Normal file
@ -0,0 +1,177 @@
|
||||
<template>
|
||||
<div class="pending-list">
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
:data="tableData"
|
||||
border={false}
|
||||
class="custom-table"
|
||||
header-row-class-name="custom-header"
|
||||
row-class-name="custom-row"
|
||||
>
|
||||
<el-table-column prop="name" label="商户名称" header-align="center" align="center" />
|
||||
<el-table-column prop="contactName" label="联系人" header-align="center" align="center" />
|
||||
<el-table-column prop="contactPhone" label="联系电话" header-align="center" align="center" />
|
||||
<el-table-column prop="contactEmail" label="联系邮箱" header-align="center" align="center" />
|
||||
<el-table-column prop="address" label="地址" header-align="center" align="center" />
|
||||
<el-table-column prop="createdAt" label="申请时间" header-align="center" align="center" />
|
||||
<el-table-column prop="status" label="状态" header-align="center" align="center">
|
||||
<template slot-scope="scope">
|
||||
<span :class="['status-tag', scope.row.status === 1 ? 'status-normal' : 'status-block']">
|
||||
{{ scope.row.status === 1 ? '正常' : '禁用' }}
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="200" header-align="center" align="center">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="text" size="mini" class="approve-btn" @click="handleApprove(scope.row)">通过</el-button>
|
||||
<el-button type="text" size="mini" class="reject-btn" @click="handleReject(scope.row)">拒绝</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { merchantList, merchantAudit } from '@/api/merchant'
|
||||
|
||||
export default {
|
||||
name: 'PendingList',
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
tableData: []
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getList()
|
||||
},
|
||||
methods: {
|
||||
async getList() {
|
||||
try {
|
||||
this.loading = true
|
||||
const res = await merchantList({
|
||||
auditStatus: 1
|
||||
})
|
||||
if (res.code === 0) {
|
||||
this.tableData = res.data.list || []
|
||||
} else {
|
||||
this.$message.error(res.message || '获取待审核列表失败')
|
||||
}
|
||||
} catch (error) {
|
||||
this.$message.error('获取待审核列表失败')
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
async handleApprove(row) {
|
||||
try {
|
||||
await this.$confirm('确认通过该商户的审核吗?', '提示', {
|
||||
type: 'warning'
|
||||
})
|
||||
const res = await merchantAudit({
|
||||
id: row.id,
|
||||
auditStatus: 2,
|
||||
auditRemark: '审核通过'
|
||||
})
|
||||
if (res.code === 0) {
|
||||
this.$message.success('审核通过成功')
|
||||
this.getList()
|
||||
} else {
|
||||
this.$message.error(res.message || '审核失败')
|
||||
}
|
||||
} catch (error) {
|
||||
if (error !== 'cancel') {
|
||||
this.$message.error('操作失败')
|
||||
}
|
||||
}
|
||||
},
|
||||
async handleReject(row) {
|
||||
try {
|
||||
const { value: rejectReason } = await this.$prompt('请输入拒绝原因', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
inputPattern: /\S+/,
|
||||
inputErrorMessage: '拒绝原因不能为空'
|
||||
})
|
||||
|
||||
const res = await merchantAudit({
|
||||
id: row.id,
|
||||
auditStatus: 3,
|
||||
rejectReason: rejectReason
|
||||
})
|
||||
|
||||
if (res.code === 0) {
|
||||
this.$message.success('已拒绝该商户')
|
||||
this.getList()
|
||||
} else {
|
||||
this.$message.error(res.message || '操作失败')
|
||||
}
|
||||
} catch (error) {
|
||||
if (error !== 'cancel') {
|
||||
this.$message.error('操作失败')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.pending-list {
|
||||
margin-top: 20px;
|
||||
}
|
||||
.custom-table {
|
||||
background: #fff;
|
||||
border: none;
|
||||
font-size: 15px;
|
||||
::v-deep .el-table__body-wrapper td,
|
||||
::v-deep .el-table__header-wrapper th {
|
||||
border-right: none !important;
|
||||
border-left: none !important;
|
||||
}
|
||||
}
|
||||
.custom-header th {
|
||||
background: #f7f8fa !important;
|
||||
color: #888;
|
||||
font-weight: 500;
|
||||
border-bottom: 1px solid #f0f0f0 !important;
|
||||
border-top: 1px solid #f0f0f0 !important;
|
||||
padding-top: 16px !important;
|
||||
padding-bottom: 16px !important;
|
||||
height: 56px !important;
|
||||
line-height: 24px !important;
|
||||
}
|
||||
.custom-row td {
|
||||
border-bottom: 1px solid #f0f0f0 !important;
|
||||
border-top: none !important;
|
||||
padding-top: 14px !important;
|
||||
padding-bottom: 14px !important;
|
||||
height: 52px !important;
|
||||
line-height: 22px !important;
|
||||
vertical-align: middle !important;
|
||||
}
|
||||
.status-tag {
|
||||
display: inline-block;
|
||||
padding: 2px 16px;
|
||||
border-radius: 16px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
}
|
||||
.status-normal {
|
||||
background: #e8f7ea;
|
||||
color: #3fc06d;
|
||||
}
|
||||
.status-block {
|
||||
background: #fbeaea;
|
||||
color: #f56c6c;
|
||||
}
|
||||
.approve-btn {
|
||||
color: #556ff6;
|
||||
font-weight: 500;
|
||||
}
|
||||
.reject-btn {
|
||||
color: #f56c6c;
|
||||
font-weight: 500;
|
||||
margin-left: 8px;
|
||||
}
|
||||
</style>
|
||||
114
src/views/merchant/components/rejected.vue
Normal file
114
src/views/merchant/components/rejected.vue
Normal file
@ -0,0 +1,114 @@
|
||||
<template>
|
||||
<div class="rejected-list">
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
:data="tableData"
|
||||
border={false}
|
||||
class="custom-table"
|
||||
header-row-class-name="custom-header"
|
||||
row-class-name="custom-row"
|
||||
>
|
||||
<el-table-column prop="name" label="商户名称" header-align="center" align="center" />
|
||||
<el-table-column prop="contactName" label="联系人" header-align="center" align="center" />
|
||||
<el-table-column prop="contactPhone" label="联系电话" header-align="center" align="center" />
|
||||
<el-table-column prop="contactEmail" label="联系邮箱" header-align="center" align="center" />
|
||||
<el-table-column prop="address" label="地址" header-align="center" align="center" />
|
||||
<el-table-column prop="auditAt" label="拒绝时间" header-align="center" align="center" />
|
||||
<el-table-column prop="rejectReason" label="拒绝原因" header-align="center" align="center" />
|
||||
<el-table-column prop="status" label="状态" header-align="center" align="center">
|
||||
<template slot-scope="scope">
|
||||
<span :class="['status-tag', scope.row.status === 1 ? 'status-normal' : 'status-block']">
|
||||
{{ scope.row.status === 1 ? '正常' : '禁用' }}
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { merchantList } from '@/api/merchant'
|
||||
|
||||
export default {
|
||||
name: 'RejectedList',
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
tableData: []
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getList()
|
||||
},
|
||||
methods: {
|
||||
async getList() {
|
||||
try {
|
||||
this.loading = true
|
||||
const res = await merchantList({
|
||||
auditStatus: 3
|
||||
})
|
||||
if (res.code === 0) {
|
||||
this.tableData = res.data.list || []
|
||||
} else {
|
||||
this.$message.error(res.message || '获取已拒绝列表失败')
|
||||
}
|
||||
} catch (error) {
|
||||
this.$message.error('获取已拒绝列表失败')
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.rejected-list {
|
||||
margin-top: 20px;
|
||||
}
|
||||
.custom-table {
|
||||
background: #fff;
|
||||
border: none;
|
||||
font-size: 15px;
|
||||
::v-deep .el-table__body-wrapper td,
|
||||
::v-deep .el-table__header-wrapper th {
|
||||
border-right: none !important;
|
||||
border-left: none !important;
|
||||
}
|
||||
}
|
||||
.custom-header th {
|
||||
background: #f7f8fa !important;
|
||||
color: #888;
|
||||
font-weight: 500;
|
||||
border-bottom: 1px solid #f0f0f0 !important;
|
||||
border-top: 1px solid #f0f0f0 !important;
|
||||
padding-top: 16px !important;
|
||||
padding-bottom: 16px !important;
|
||||
height: 56px !important;
|
||||
line-height: 24px !important;
|
||||
}
|
||||
.custom-row td {
|
||||
border-bottom: 1px solid #f0f0f0 !important;
|
||||
border-top: none !important;
|
||||
padding-top: 14px !important;
|
||||
padding-bottom: 14px !important;
|
||||
height: 52px !important;
|
||||
line-height: 22px !important;
|
||||
vertical-align: middle !important;
|
||||
}
|
||||
.status-tag {
|
||||
display: inline-block;
|
||||
padding: 2px 16px;
|
||||
border-radius: 16px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
}
|
||||
.status-normal {
|
||||
background: #e8f7ea;
|
||||
color: #3fc06d;
|
||||
}
|
||||
.status-block {
|
||||
background: #fbeaea;
|
||||
color: #f56c6c;
|
||||
}
|
||||
</style>
|
||||
123
src/views/merchant/merchant-list.vue
Normal file
123
src/views/merchant/merchant-list.vue
Normal file
@ -0,0 +1,123 @@
|
||||
<template>
|
||||
<div class="merchant-list">
|
||||
<div class="search-area">
|
||||
<el-form :inline="true" :model="searchForm" class="search-form">
|
||||
<el-form-item label="商户名称">
|
||||
<el-input v-model="searchForm.name" placeholder="请输入商户名称" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="联系人">
|
||||
<el-input v-model="searchForm.contactName" placeholder="请输入联系人" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="联系电话">
|
||||
<el-input v-model="searchForm.contactPhone" placeholder="请输入联系电话" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleSearch">搜索</el-button>
|
||||
<el-button @click="handleReset">重置</el-button>
|
||||
<el-button type="text" class="refresh-btn" @click="handleRefresh">
|
||||
<i class="el-icon-refresh"></i>
|
||||
刷新
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<div class="status-tabs">
|
||||
<el-tabs v-model="activeTab" @tab-click="handleTabClick">
|
||||
<el-tab-pane label="待审核" name="pending">
|
||||
<pending-list ref="pendingList" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="已通过" name="approved">
|
||||
<approved-list ref="approvedList" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="已拒绝" name="rejected">
|
||||
<rejected-list ref="rejectedList" />
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import PendingList from './components/pending.vue'
|
||||
import ApprovedList from './components/approved.vue'
|
||||
import RejectedList from './components/rejected.vue'
|
||||
|
||||
export default {
|
||||
name: 'MerchantList',
|
||||
components: {
|
||||
PendingList,
|
||||
ApprovedList,
|
||||
RejectedList
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
activeTab: 'pending',
|
||||
searchForm: {
|
||||
name: '',
|
||||
contactName: '',
|
||||
contactPhone: ''
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
// 确保默认选中待审核标签页
|
||||
this.activeTab = 'pending'
|
||||
},
|
||||
methods: {
|
||||
handleSearch() {
|
||||
this.$refs[`${this.activeTab}List`].getList()
|
||||
},
|
||||
handleReset() {
|
||||
this.searchForm = {
|
||||
name: '',
|
||||
contactName: '',
|
||||
contactPhone: ''
|
||||
}
|
||||
this.$refs[`${this.activeTab}List`].getList()
|
||||
},
|
||||
handleTabClick(tab) {
|
||||
this.activeTab = tab.name
|
||||
this.$refs[`${this.activeTab}List`].getList()
|
||||
},
|
||||
handleRefresh() {
|
||||
this.$refs[`${this.activeTab}List`].getList()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.merchant-list {
|
||||
padding: 20px;
|
||||
background: #fff;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.search-area {
|
||||
margin-bottom: 20px;
|
||||
padding: 20px;
|
||||
background: #f7f8fa;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.search-form {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
::v-deep .el-form-item {
|
||||
margin-bottom: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
.refresh-btn {
|
||||
margin-left: 8px;
|
||||
color: #556ff6;
|
||||
font-weight: 500;
|
||||
i {
|
||||
margin-right: 4px;
|
||||
}
|
||||
}
|
||||
.status-tabs {
|
||||
background: #fff;
|
||||
padding: 20px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
</style>
|
||||
0
src/views/user/feedback-list.vue
Normal file
0
src/views/user/feedback-list.vue
Normal file
288
src/views/user/user-list.vue
Normal file
288
src/views/user/user-list.vue
Normal file
@ -0,0 +1,288 @@
|
||||
<template>
|
||||
<div class="user-list-page">
|
||||
<div class="search-row">
|
||||
<el-input
|
||||
v-model="searchForm.nickname"
|
||||
placeholder="搜索用户..."
|
||||
prefix-icon="el-icon-search"
|
||||
class="search-input"
|
||||
@keyup.enter.native="handleSearch"
|
||||
clearable
|
||||
/>
|
||||
<div class="user-action">
|
||||
<el-button type="primary" class="add-btn" @click="onAdd">添加用户</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-card">
|
||||
<el-table
|
||||
:data="tableData"
|
||||
v-loading="tableLoading"
|
||||
border={false}
|
||||
class="custom-table"
|
||||
header-row-class-name="custom-header"
|
||||
row-class-name="custom-row"
|
||||
>
|
||||
<el-table-column label="用户信息" min-width="300">
|
||||
<template slot-scope="scope">
|
||||
<div class="user-info-cell">
|
||||
<el-avatar :size="48" :src="scope.row.avatar">
|
||||
<span class="avatar-text">{{ scope.row.nickname ? scope.row.nickname.substr(0,1) : '?' }}</span>
|
||||
</el-avatar>
|
||||
<div class="user-info-text">
|
||||
<div class="nickname">{{ scope.row.nickname || '-' }}</div>
|
||||
<div class="username">{{ scope.row.username || '-' }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="phone" label="手机号" width="300" align="center">
|
||||
<template slot-scope="scope">
|
||||
{{ scope.row.phone || '-' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="status" label="状态" width="100" align="center">
|
||||
<template slot-scope="scope">
|
||||
<span :class="['status-tag', scope.row.status === 0 ? 'status-normal' : 'status-block']">
|
||||
{{ scope.row.status === 0 ? '正常' : '禁用' }}
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="birthday" label="注册时间" width="200" align="center">
|
||||
<template slot-scope="scope">
|
||||
{{ scope.row.birthday ? scope.row.birthday : '-' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="lastLoginStoreName" label="最近登录门店" width="200" align="center" />
|
||||
<el-table-column label="操作" width="120" align="center">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="text" size="mini" class="edit-btn" @click="onEdit(scope.row)">编辑</el-button>
|
||||
<el-button type="text" size="mini" class="delete-btn" @click="onDeleteSingle(scope.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="table-footer">
|
||||
<div class="table-summary">
|
||||
显示第 {{ (searchForm.page - 1) * searchForm.pageSize + 1 }} 到
|
||||
{{ Math.min(searchForm.page * searchForm.pageSize, total) }} 条,共 {{ total }} 条记录
|
||||
</div>
|
||||
<el-pagination
|
||||
background
|
||||
layout="prev, pager, next"
|
||||
:current-page="searchForm.page"
|
||||
:page-size="searchForm.pageSize"
|
||||
:total="total"
|
||||
@current-change="handleCurrentChange"
|
||||
class="custom-pagination"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { userList, deleteUser, batchDeleteUsers } from '@/api/user'
|
||||
|
||||
export default {
|
||||
name: 'UserList',
|
||||
data() {
|
||||
return {
|
||||
tableLoading: false,
|
||||
tableData: [],
|
||||
total: 0,
|
||||
searchForm: {
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
nickname: ''
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getList()
|
||||
},
|
||||
methods: {
|
||||
async getList() {
|
||||
this.tableLoading = true
|
||||
try {
|
||||
const res = await userList(this.searchForm)
|
||||
if (res.code === 0) {
|
||||
this.tableData = res.data.list
|
||||
this.total = res.data.total
|
||||
} else {
|
||||
this.$message.error(res.message || '获取数据失败')
|
||||
}
|
||||
} catch (error) {
|
||||
this.$message.error('获取数据失败')
|
||||
console.error(error)
|
||||
} finally {
|
||||
this.tableLoading = false
|
||||
}
|
||||
},
|
||||
handleSearch() {
|
||||
this.searchForm.page = 1
|
||||
this.getList()
|
||||
},
|
||||
handleCurrentChange(val) {
|
||||
this.searchForm.page = val
|
||||
this.getList()
|
||||
},
|
||||
onAdd() {
|
||||
// TODO: 实现添加用户弹窗
|
||||
this.$message.info('添加用户功能待实现')
|
||||
},
|
||||
onEdit(row) {
|
||||
// TODO: 实现编辑功能
|
||||
this.$message.info('编辑功能待实现')
|
||||
},
|
||||
async onDeleteSingle(row) {
|
||||
try {
|
||||
await this.$confirm('确认删除该用户吗?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
})
|
||||
const res = await deleteUser(row.id)
|
||||
if (res.code === 0) {
|
||||
this.$message.success('删除成功')
|
||||
this.getList()
|
||||
} else {
|
||||
this.$message.error(res.message || '删除失败')
|
||||
}
|
||||
} catch (error) {
|
||||
if (error !== 'cancel') {
|
||||
this.$message.error('删除失败')
|
||||
console.error(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.user-list-page {
|
||||
background: #fff;
|
||||
min-height: 100vh;
|
||||
padding: 0 32px 32px 32px;
|
||||
}
|
||||
.search-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-top: 20px;
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
.search-input {
|
||||
width: 320px;
|
||||
background: #fff;
|
||||
border-radius: 6px;
|
||||
}
|
||||
.user-action .add-btn {
|
||||
background: #556ff6;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
font-weight: 500;
|
||||
}
|
||||
.table-card {
|
||||
background: #fff;
|
||||
border-radius: 10px;
|
||||
box-shadow: none;
|
||||
padding: 0 0 12px 0;
|
||||
}
|
||||
.custom-table {
|
||||
background: #fff;
|
||||
border: none;
|
||||
font-size: 15px;
|
||||
::v-deep .el-table__body-wrapper td,
|
||||
::v-deep .el-table__header-wrapper th {
|
||||
border-right: none !important;
|
||||
border-left: none !important;
|
||||
}
|
||||
}
|
||||
.custom-header th {
|
||||
background: #f7f8fa !important;
|
||||
color: #888;
|
||||
font-weight: 500;
|
||||
border-bottom: 1px solid #f0f0f0 !important;
|
||||
border-top: 1px solid #f0f0f0 !important;
|
||||
padding-top: 16px !important;
|
||||
padding-bottom: 16px !important;
|
||||
height: 56px !important;
|
||||
line-height: 24px !important;
|
||||
}
|
||||
.custom-row td {
|
||||
border-bottom: 1px solid #f0f0f0 !important;
|
||||
border-top: none !important;
|
||||
padding-top: 14px !important;
|
||||
padding-bottom: 14px !important;
|
||||
height: 52px !important;
|
||||
line-height: 22px !important;
|
||||
vertical-align: middle !important;
|
||||
}
|
||||
.user-info-cell {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.user-info-cell .el-avatar {
|
||||
margin-right: 16px;
|
||||
background: #e3e6f0;
|
||||
color: #556ff6;
|
||||
font-weight: bold;
|
||||
}
|
||||
.user-info-text .nickname {
|
||||
font-weight: 600;
|
||||
color: #222;
|
||||
font-size: 16px;
|
||||
}
|
||||
.user-info-text .username {
|
||||
color: #888;
|
||||
font-size: 13px;
|
||||
margin-top: 2px;
|
||||
}
|
||||
.status-tag {
|
||||
display: inline-block;
|
||||
padding: 2px 16px;
|
||||
border-radius: 16px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
background: #e8f7ea;
|
||||
color: #3fc06d;
|
||||
}
|
||||
.status-block {
|
||||
background: #fbeaea;
|
||||
color: #f56c6c;
|
||||
}
|
||||
.table-footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-top: 8px;
|
||||
padding: 0 12px;
|
||||
}
|
||||
.table-summary {
|
||||
color: #888;
|
||||
font-size: 13px;
|
||||
}
|
||||
.custom-pagination {
|
||||
.el-pager li {
|
||||
border-radius: 6px;
|
||||
min-width: 32px;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
font-size: 15px;
|
||||
}
|
||||
}
|
||||
.edit-btn {
|
||||
color: #556ff6;
|
||||
font-weight: 500;
|
||||
}
|
||||
.delete-btn {
|
||||
color: #f56c6c;
|
||||
font-weight: 500;
|
||||
margin-left: 8px;
|
||||
}
|
||||
::v-deep .el-breadcrumb__inner,
|
||||
::v-deep .el-breadcrumb__inner a {
|
||||
font-size: 18px !important;
|
||||
font-weight: 500;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user