admin.xpcool.com/apps/web-tdesign/src/views/system/admin/index.vue
夏犀麟 0ab6cf5f17
Some checks failed
Build and Deploy (admin.xpcool.com) / build-and-deploy (push) Failing after 5m25s
CHG: 登录页去除账号下拉与内置密码;house 模块前端;Gitea act_runner 自动部署 workflow
- 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
2026-08-26 23:55:07 +08:00

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>