Some checks failed
Build and Deploy (admin.xpcool.com) / build-and-deploy (push) Failing after 5m25s
- login.vue:移除 selectAccount 下拉与 MOCK_USER_OPTIONS(代码不存账号密码),手输+记住账号
- .env.production:VITE_GLOB_API_URL=/api/service(同源反代)
- house:api/house.ts + views/house/{community,listing,dashboard,data}
- .gitea/workflows/deploy.yml:node22 + pnpm11.16 + vite 直跑构建 → /data/www/admin.xpcool.com
236 lines
6.2 KiB
Vue
236 lines
6.2 KiB
Vue
<script lang="ts" setup>
|
|
import type { AdminItem, RoleItem } from '#/api/system';
|
|
|
|
import { onMounted, reactive, ref } from 'vue';
|
|
|
|
import { useAccess } from '@vben/access';
|
|
import { Page } from '@vben/common-ui';
|
|
|
|
import { DialogPlugin, MessagePlugin } from 'tdesign-vue-next';
|
|
|
|
import {
|
|
createAdmin,
|
|
deleteAdmin,
|
|
getAdminList,
|
|
getRoleList,
|
|
resetAdminPassword,
|
|
updateAdmin,
|
|
} from '#/api/system';
|
|
|
|
const { hasAccessByCodes } = useAccess();
|
|
|
|
const loading = ref(false);
|
|
const list = ref<AdminItem[]>([]);
|
|
const roleOptions = ref<{ label: string; value: number }[]>([]);
|
|
const dialogOpen = ref(false);
|
|
const editing = ref<null | AdminItem>(null);
|
|
|
|
const query = reactive({ page: 1, size: 10, keyword: '' });
|
|
const pagination = reactive({ current: 1, pageSize: 10, total: 0 });
|
|
const form = reactive({
|
|
username: '',
|
|
password: '',
|
|
nickname: '',
|
|
status: 1,
|
|
roleIds: [] as number[],
|
|
});
|
|
|
|
async function load() {
|
|
loading.value = true;
|
|
try {
|
|
const data = await getAdminList(query);
|
|
list.value = data.list ?? [];
|
|
pagination.total = data.total ?? 0;
|
|
} finally {
|
|
loading.value = false;
|
|
}
|
|
}
|
|
|
|
async function loadRoles() {
|
|
const data = await getRoleList({ page: 1, size: 100 });
|
|
roleOptions.value = (data.list ?? []).map((r: RoleItem) => ({
|
|
label: r.name,
|
|
value: r.id,
|
|
}));
|
|
}
|
|
|
|
function openCreate() {
|
|
editing.value = null;
|
|
Object.assign(form, { username: '', password: '', nickname: '', status: 1, roleIds: [] });
|
|
dialogOpen.value = true;
|
|
}
|
|
|
|
function openEdit(row: AdminItem) {
|
|
editing.value = row;
|
|
Object.assign(form, {
|
|
username: row.username,
|
|
password: '',
|
|
nickname: row.nickname,
|
|
status: row.status,
|
|
roleIds: row.roleIds ?? [],
|
|
});
|
|
dialogOpen.value = true;
|
|
}
|
|
|
|
async function submit() {
|
|
if (editing.value) {
|
|
await updateAdmin(editing.value.id, {
|
|
nickname: form.nickname,
|
|
status: form.status,
|
|
roleIds: form.roleIds,
|
|
});
|
|
} else {
|
|
await createAdmin({
|
|
username: form.username,
|
|
password: form.password,
|
|
nickname: form.nickname,
|
|
roleIds: form.roleIds,
|
|
});
|
|
}
|
|
MessagePlugin.success('保存成功');
|
|
dialogOpen.value = false;
|
|
load();
|
|
}
|
|
|
|
function onDelete(row: AdminItem) {
|
|
const d = DialogPlugin.confirm({
|
|
header: '确认删除该人员?',
|
|
onConfirm: async () => {
|
|
await deleteAdmin(row.id);
|
|
MessagePlugin.success('删除成功');
|
|
load();
|
|
d.destroy();
|
|
},
|
|
});
|
|
}
|
|
|
|
function onResetPwd(row: AdminItem) {
|
|
let password = '';
|
|
const d = DialogPlugin.confirm({
|
|
header: `重置「${row.username}」的密码`,
|
|
body: '请输入新密码(至少 6 位)',
|
|
onConfirm: async () => {
|
|
if (!password || password.length < 6) {
|
|
MessagePlugin.warning('密码至少 6 位');
|
|
return;
|
|
}
|
|
await resetAdminPassword(row.id, password);
|
|
MessagePlugin.success('密码已重置');
|
|
d.destroy();
|
|
},
|
|
});
|
|
}
|
|
|
|
const columns = [
|
|
{ colKey: 'id', title: 'ID', width: 70 },
|
|
{ colKey: 'username', title: '用户名' },
|
|
{ colKey: 'nickname', title: '昵称' },
|
|
{ colKey: 'statusText', title: '状态', width: 90 },
|
|
{ colKey: 'roleNamesText', title: '角色' },
|
|
{ colKey: 'createdAt', title: '创建时间', width: 170 },
|
|
{ colKey: 'op', title: '操作', width: 200 },
|
|
];
|
|
|
|
function onPageChange(p: { current: number; pageSize: number }) {
|
|
query.page = p.current;
|
|
query.size = p.pageSize;
|
|
pagination.current = p.current;
|
|
pagination.pageSize = p.pageSize;
|
|
load();
|
|
}
|
|
|
|
onMounted(() => {
|
|
load();
|
|
loadRoles();
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<Page auto-content-height>
|
|
<div class="mb-3 flex items-center justify-between">
|
|
<div class="flex items-center gap-2">
|
|
<t-input
|
|
v-model="query.keyword"
|
|
clearable
|
|
placeholder="用户名/昵称"
|
|
style="width: 220px"
|
|
@enter="load"
|
|
/>
|
|
<t-button theme="primary" @click="load">查询</t-button>
|
|
</div>
|
|
<t-button
|
|
v-if="hasAccessByCodes(['system:personnel:create'])"
|
|
theme="primary"
|
|
@click="openCreate"
|
|
>
|
|
新增人员
|
|
</t-button>
|
|
</div>
|
|
|
|
<t-table
|
|
row-key="id"
|
|
:data="list"
|
|
:columns="columns"
|
|
:loading="loading"
|
|
:pagination="pagination"
|
|
@page-change="onPageChange"
|
|
>
|
|
<template #statusText="{ row }">{{ row.status === 1 ? '启用' : '禁用' }}</template>
|
|
<template #roleNamesText="{ row }">{{ (row.roleNames ?? []).join(', ') }}</template>
|
|
<template #op="{ row }">
|
|
<t-button
|
|
v-if="hasAccessByCodes(['system:personnel:update'])"
|
|
size="small"
|
|
theme="primary"
|
|
variant="text"
|
|
@click="openEdit(row)"
|
|
>
|
|
编辑
|
|
</t-button>
|
|
<t-button
|
|
v-if="hasAccessByCodes(['system:personnel:resetPwd'])"
|
|
size="small"
|
|
theme="primary"
|
|
variant="text"
|
|
@click="onResetPwd(row)"
|
|
>
|
|
重置密码
|
|
</t-button>
|
|
<t-button
|
|
v-if="hasAccessByCodes(['system:personnel:delete'])"
|
|
size="small"
|
|
theme="danger"
|
|
variant="text"
|
|
@click="onDelete(row)"
|
|
>
|
|
删除
|
|
</t-button>
|
|
</template>
|
|
</t-table>
|
|
|
|
<t-dialog
|
|
v-model:visible="dialogOpen"
|
|
:header="editing ? '编辑人员' : '新增人员'"
|
|
:on-confirm="submit"
|
|
>
|
|
<t-form label-align="right" label-width="80px">
|
|
<t-form-item label="用户名" required>
|
|
<t-input v-model="form.username" :disabled="!!editing" placeholder="登录用户名" />
|
|
</t-form-item>
|
|
<t-form-item v-if="!editing" label="密码" required>
|
|
<t-input v-model="form.password" type="password" placeholder="至少 6 位" />
|
|
</t-form-item>
|
|
<t-form-item label="昵称">
|
|
<t-input v-model="form.nickname" placeholder="显示名称" />
|
|
</t-form-item>
|
|
<t-form-item label="状态">
|
|
<t-switch v-model="form.status" :custom-value="[1, 0]" />
|
|
</t-form-item>
|
|
<t-form-item label="角色">
|
|
<t-select v-model="form.roleIds" multiple :options="roleOptions" placeholder="选择角色" />
|
|
</t-form-item>
|
|
</t-form>
|
|
</t-dialog>
|
|
</Page>
|
|
</template>
|