You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

364 lines
9.8 KiB

<template>
<div>
<div class="title">用户管理</div>
<el-form
ref="searchFormRef"
class="form"
:inline="true"
label-width="98px"
:model="queryParams"
>
<el-form-item label="用户名称" prop="username">
<el-input
clearable
placeholder="请输入"
style="width: 220px"
v-model="queryParams.username"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label-width="100px">
<el-button icon="Search" type="primary" @click="handleQuery"> 搜索 </el-button>
<el-button icon="RefreshRight" @click="resetQuery"> 重置 </el-button>
</el-form-item>
</el-form>
<div style="margin-bottom: 20px">
<el-button icon="Plus" type="primary" @click="add"> 新建 </el-button>
</div>
<div ref="tableContainerEl" class="table_border table">
<el-table
ref="tableRef"
:data="tableData"
v-loading="loading"
header-row-class-name="table-header"
>
<el-table-column align="center" label="用户名" prop="username" show-overflow-tooltip />
<el-table-column align="center" label="电话" prop="phone" show-overflow-tooltip />
<el-table-column align="center" label="邮件" prop="email" show-overflow-tooltip />
<el-table-column align="center" label="角色" prop="roles">
<template #default="{ row }">
{{ row.roles?.map((item) => item.name)?.join(',') }}
</template>
</el-table-column>
<el-table-column align="center" label="厂商" prop="vendors">
<template #default="{ row }">
{{ row.vendors?.map((item) => item.name)?.join(',') }}
</template>
</el-table-column>
<el-table-column align="center" label="操作" width="180">
<template #default="{ row }">
<div class="flex items-center">
<el-button link type="primary" @click="editRole(row)"> 分配角色 </el-button>
<el-button link type="primary" @click="edit(row)"> 编辑 </el-button>
<el-button link type="danger" @click="handleDelete(row)"> 删除 </el-button>
</div>
<template v-if="useUserStore().userInfo?.isAdmin">
<div class="flex items-center">
<el-button link type="primary" @click="order(row)"> 赠送套餐 </el-button>
<el-button link type="primary" @click="pay(row)"> 充值 </el-button>
</div>
<div class="flex items-center">
<el-button link type="primary" @click="vendor(row, 'authorize')">
分配厂商
</el-button>
<el-button
link
type="primary"
v-if="row.vendors?.length > 0"
@click="vendor(row, 'revoke')"
>
撤销厂商
</el-button>
</div>
</template>
</template>
</el-table-column>
</el-table>
</div>
<pagination
v-show="total > 0"
:total="total"
v-model:limit="queryParams.limit"
v-model:page="queryParams.page"
@pagination="getList"
/>
<HandleDialog
v-if="isShowDialog"
:type="rowType"
:row="currentRow"
@closed="isShowDialog = false"
@on-success="getList"
/>
<RoleDialog
v-if="isShowRoleDialog"
:row="currentRow"
:roleList="roleList"
@closed="isShowRoleDialog = false"
@on-success="getList"
/>
<el-dialog
align-center
title="充值"
width="500"
v-model="isShowPayDialog"
@closed="payClosed"
:close-on-click-modal="false"
>
是否给【{{ currentRow.username }}】进行充值
<el-input-number v-model="pay_amount"></el-input-number>元
<template #footer>
<div class="dialog-footer">
<el-button @click="payClosed"> 取 消 </el-button>
<el-button type="primary" :loading="payLoading" @click="payConfirm"> 确 定 </el-button>
</div>
</template>
</el-dialog>
<el-dialog
align-center
title="赠送套餐"
width="500"
v-model="isShowOrderDialog"
@closed="orderClosed"
:close-on-click-modal="false"
>
是否给【{{ currentRow.username }}】进行赠送
<el-select v-model="order_id">
<el-option v-for="item in planList" :value="item.id" :label="item.name"></el-option>
</el-select>
<template #footer>
<div class="dialog-footer">
<el-button @click="orderClosed"> 取 消 </el-button>
<el-button type="primary" :loading="orderLoading" @click="orderConfirm">
确 定
</el-button>
</div>
</template>
</el-dialog>
<el-dialog
align-center
:title="currentType === 'authorize' ? '分配厂商' : '撤销厂商'"
width="500"
v-model="isShowVendorDialog"
@closed="vendorClosed"
:close-on-click-modal="false"
>
<el-checkbox-group v-model="vendorSelected">
<el-checkbox v-for="item in vendorListFilter" :label="item.name" :value="item.id" />
</el-checkbox-group>
<template #footer>
<div class="dialog-footer">
<el-button @click="vendorClosed"> 取 消 </el-button>
<el-button type="primary" :loading="vendorLoading" @click="vendorConfirm">
</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup>
import { useTableRPC } from '@/utils/hook'
import dayjs from 'dayjs'
import RPC from '@/utils/rpc'
import HandleDialog from './HandleDialog.vue'
import RoleDialog from './RoleDialog.vue'
import { useUserStore } from '@/stores/user'
const rowType = ref('')
const currentRow = ref(null)
const add = () => {
isShowDialog.value = true
currentRow.value = null
rowType.value = 'add'
}
const edit = (row) => {
isShowDialog.value = true
rowType.value = 'edit'
currentRow.value = row
}
const editRole = (row) => {
isShowRoleDialog.value = true
currentRow.value = row
}
const isShowRoleDialog = ref(false)
const roleList = ref([])
RPC.post('/role/list', { page: 1, limit: -1 }).then((res) => {
roleList.value = res.rows || []
})
const pay_amount = ref(0)
const isShowPayDialog = ref(false)
const payLoading = ref(false)
const payClosed = () => {
isShowPayDialog.value = false
currentRow.value = {}
}
const pay = (row) => {
currentRow.value = row
isShowPayDialog.value = true
pay_amount.value = 0
}
const payConfirm = () => {
if (!pay_amount.value) {
ElMessage.warning('请填写充值金额')
return
}
payLoading.value = true
RPC.post('/wallet/admin/recharge_and_pay', {
user_id: currentRow.value.id,
amount_cents: pay_amount.value * 100,
pay_channel: 'admin',
remark: '手动充值',
})
.then(() => {
isShowPayDialog.value = false
ElMessage.success('充值成功')
getList()
})
.finally(() => {
payLoading.value = false
})
}
const planList = ref([])
RPC.post('/membership_plan/list', { page: 0, limit: -1, orderby: [{ sort: 'asc' }] }).then(
(res) => {
planList.value = res.rows || []
},
)
const order_id = ref(0)
const isShowOrderDialog = ref(false)
const orderLoading = ref(false)
const orderClosed = () => {
isShowOrderDialog.value = false
currentRow.value = {}
order_id.value = null
}
const order = (row) => {
currentRow.value = row
isShowOrderDialog.value = true
order_id.value = null
}
const orderConfirm = () => {
if (!order_id) {
ElMessage.warning('请选择赠送套餐')
return
}
orderLoading.value = true
RPC.post('/membership/admin/order/create_and_pay', {
user_id: currentRow.value.id,
plan_id: order_id.value,
pay_channel: 'admin',
remark: '管理员手动完成',
})
.then(() => {
isShowOrderDialog.value = false
ElMessage.success('赠送成功')
getList()
})
.finally(() => {
orderLoading.value = false
})
}
const isShowVendorDialog = ref(false)
const vendorLoading = ref(false)
const vendorClosed = () => {
isShowVendorDialog.value = false
currentRow.value = {}
vendorSelected.value = []
}
const currentType = ref('')
const vendor = (row, type) => {
if (type === 'authorize') {
vendorListFilter.value = vendorList.value
vendorSelected.value = row.vendors.map((item) => item.vendor_id)
}
if (type === 'revoke') {
vendorListFilter.value = row.vendors.map((item) => {
return {
id: item.vendor_id,
...item,
}
})
}
currentType.value = type
currentRow.value = row
isShowVendorDialog.value = true
}
const vendorConfirm = () => {
if (vendorSelected?.value.length <= 0) {
ElMessage.warning('请选择厂商')
return
}
vendorLoading.value = true
RPC.post(`/vendor_user_${currentType.value}`, {
user_id: currentRow.value.id,
vendor_ids: vendorSelected.value,
})
.then(() => {
isShowVendorDialog.value = false
ElMessage.success('操作成功')
getList()
})
.finally(() => {
vendorLoading.value = false
})
}
const vendorList = ref([])
const vendorListFilter = ref([])
const vendorSelected = ref([])
RPC.post('/vendor/list', { page: 1, limit: -1 }).then((res) => {
vendorList.value = res.rows || []
})
const {
loading,
tableData,
tableRef,
searchFormRef,
total,
queryParams,
getList,
handleQuery,
resetQuery,
handleDelete,
isShowDialog,
maxHeight,
tableContainerEl,
} = useTableRPC({
queryParams: {},
remoteDataFn: '/user/list',
deleteConfig: {
remote: '/user/delete',
key: 'id',
message(row) {
return `确认删除 “${row.username}`
},
},
})
getList()
</script>
<style lang="scss" scoped>
.title {
font-size: 20px;
font-weight: 700;
margin-bottom: 20px;
}
</style>