97 lines
3.4 KiB
Vue
97 lines
3.4 KiB
Vue
<script setup>
|
|
import { onMounted, reactive, ref } from 'vue'
|
|
import { message } from 'ant-design-vue'
|
|
import { userListApi, userSetLevelApi, userStatusApi } from '@/api/request/user'
|
|
import { levelListApi } from '@/api/request/level'
|
|
|
|
const loading = ref(false)
|
|
const list = ref([])
|
|
const total = ref(0)
|
|
const levels = ref([])
|
|
const query = reactive({ page: 1, pageSize: 20, keyword: '' })
|
|
|
|
const columns = [
|
|
{ title: '用户', key: 'name' },
|
|
{ title: 'openid', dataIndex: 'openid', key: 'openid', ellipsis: true },
|
|
{ title: '等级', key: 'level', width: 140 },
|
|
{ title: '使用次数', dataIndex: 'usageCount', key: 'usageCount', width: 100 },
|
|
{ title: '最近使用', dataIndex: 'lastUsedAt', key: 'lastUsedAt', width: 170 },
|
|
{ title: '注册时间', dataIndex: 'createdAt', key: 'createdAt', width: 170 },
|
|
{ title: '状态', key: 'status', width: 80 },
|
|
]
|
|
|
|
async function load() {
|
|
loading.value = true
|
|
try {
|
|
const res = await userListApi({ ...query, keyword: query.keyword || undefined })
|
|
list.value = res.list
|
|
total.value = res.total
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
async function loadLevels() {
|
|
const res = await levelListApi()
|
|
levels.value = res.list.filter((l) => l.isEnabled === 1)
|
|
}
|
|
|
|
onMounted(() => {
|
|
load()
|
|
loadLevels()
|
|
})
|
|
|
|
async function setLevel(record, levelKey) {
|
|
await userSetLevelApi({ userId: record.id, levelKey })
|
|
record.levelKey = levelKey
|
|
const target = levels.value.find((l) => l.levelKey === levelKey)
|
|
record.levelName = target?.name || levelKey
|
|
message.success(`已设为 ${record.levelName}`)
|
|
}
|
|
|
|
async function toggleStatus(record) {
|
|
await userStatusApi({ userId: record.id, status: record.status })
|
|
message.success(record.status === 1 ? '已启用' : '已禁用')
|
|
}
|
|
|
|
function onTableChange(pag) {
|
|
query.page = pag.current
|
|
query.pageSize = pag.pageSize
|
|
load()
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div class="flex flex-col gap-4">
|
|
<a-input-search v-model:value="query.keyword" placeholder="昵称 / openid" style="width: 280px" allowClear
|
|
@search="load" />
|
|
|
|
<a-table :columns="columns" :data-source="list" row-key="id" :loading="loading"
|
|
:pagination="{ current: query.page, pageSize: query.pageSize, total, showSizeChanger: false }"
|
|
@change="onTableChange">
|
|
<template #bodyCell="{ column, record }">
|
|
<template v-if="column.key === 'name'">
|
|
<div class="flex items-center gap-2">
|
|
<span class="inline-flex w-9 h-9 rounded-xl bg-[#FFF1E8] items-center justify-center text-[#E8531A]">
|
|
<template v-if="record.avatarUrl">
|
|
<img :src="record.avatarUrl" class="w-9 h-9 rounded-xl object-cover" alt="" />
|
|
</template>
|
|
<template v-else>{{ (record.nickname || '微').slice(0, 1) }}</template>
|
|
</span>
|
|
<span class="font-medium text-slate-700">{{ record.nickname }}</span>
|
|
</div>
|
|
</template>
|
|
<template v-else-if="column.key === 'level'">
|
|
<a-select :value="record.levelKey" size="small" style="width: 110px"
|
|
:options="levels.map((l) => ({ value: l.levelKey, label: l.name }))"
|
|
@change="(v) => setLevel(record, v)" />
|
|
</template>
|
|
<template v-else-if="column.key === 'status'">
|
|
<a-switch :checked="record.status === 1" size="small"
|
|
@change="(v) => { record.status = v ? 1 : 0; toggleStatus(record) }" />
|
|
</template>
|
|
</template>
|
|
</a-table>
|
|
</div>
|
|
</template>
|