经理用户

This commit is contained in:
zhx 2026-05-06 15:07:10 +08:00
parent 96c224f71d
commit 60ab0ebf17
4 changed files with 422 additions and 0 deletions

View File

@ -197,6 +197,15 @@ export async function pageBdLead(params: Record<string, any>) {
);
}
export async function pageTeamManager(params: Record<string, any>) {
return requestClient.get<LegacyPageResult<Record<string, any>>>(
'/team/manager/page',
{
params,
},
);
}
export async function pageBdTable(params: Record<string, any>) {
return requestClient.get<LegacyPageResult<Record<string, any>>>(
'/team/bd/page',
@ -260,3 +269,17 @@ export async function leadBindBd(data: Record<string, any>) {
export async function teamBindBd(data: Record<string, any>) {
return requestClient.post('/team/bind/bd', data);
}
export async function deleteTeamManager(id: number | string) {
return requestClient.get('/team/manager/del', {
params: { id },
});
}
export async function addTeamManager(data: Record<string, any>) {
return requestClient.post('/team/manager/add', data);
}
export async function updateTeamManager(data: Record<string, any>) {
return requestClient.post('/team/manager/update', data);
}

View File

@ -34,6 +34,12 @@ const routes: RouteRecordRaw[] = [
component: () => import('#/views/team/member-list.vue'),
meta: { title: '成员列表' },
},
{
name: 'TeamManagerList',
path: 'team/manager',
component: () => import('#/views/team/manager-list.vue'),
meta: { title: '经理列表' },
},
{
name: 'TeamBillList',
path: 'team/bill',

View File

@ -0,0 +1,119 @@
<script lang="ts" setup>
import { computed, reactive, ref, watch } from 'vue';
import {
addTeamManager,
updateTeamManager,
} from '#/api/legacy/team';
import AccountInput from '#/components/account-input.vue';
import SystemRegionSelect from '#/views/operate/components/system-region-select.vue';
import {
Form,
FormItem,
Input,
Modal,
message,
} from 'antdv-next';
const props = defineProps<{
open: boolean;
row: null | Record<string, any>;
sysOrigin: string;
}>();
const emit = defineEmits<{
close: [];
success: [];
}>();
const saving = ref(false);
const form = reactive({
contact: '',
id: '',
regionId: '',
sysOrigin: '',
userId: '',
});
const isUpdate = computed(() => Boolean(props.row?.id));
const title = computed(() => (isUpdate.value ? '修改经理' : '添加经理'));
watch(
() => props.open,
(open) => {
if (!open) {
return;
}
form.id = String(props.row?.id || '');
form.userId = String(props.row?.userId || props.row?.userProfile?.id || '');
form.sysOrigin = props.row?.sysOrigin || props.sysOrigin || 'LIKEI';
form.contact = props.row?.contact || '';
form.regionId = String(props.row?.regionId || '');
},
{ immediate: true },
);
async function handleSubmit() {
if (!isUpdate.value && !String(form.userId || '').trim()) {
message.warning('请输入经理用户ID');
return;
}
if (!form.regionId) {
message.warning('请选择区域');
return;
}
saving.value = true;
try {
const payload = {
contact: form.contact.trim(),
id: form.id || undefined,
regionId: form.regionId,
sysOrigin: form.sysOrigin,
userId: form.userId,
};
if (isUpdate.value) {
await updateTeamManager(payload);
} else {
await addTeamManager(payload);
}
message.success('保存成功');
emit('success');
emit('close');
} finally {
saving.value = false;
}
}
</script>
<template>
<Modal
:confirm-loading="saving"
destroy-on-close
:open="open"
:title="title"
@cancel="emit('close')"
@ok="handleSubmit"
>
<Form layout="vertical">
<FormItem v-if="!isUpdate" label="经理ID">
<AccountInput
v-model:value="form.userId"
placeholder="经理用户ID"
:sys-origin="form.sysOrigin"
/>
</FormItem>
<FormItem label="区域">
<SystemRegionSelect
v-model:value="form.regionId"
placeholder="请选择区域"
:sys-origin="form.sysOrigin"
/>
</FormItem>
<FormItem label="联系方式">
<Input v-model:value="form.contact" placeholder="联系方式" />
</FormItem>
</Form>
</Modal>
</template>

View File

@ -0,0 +1,274 @@
<script lang="ts" setup>
import { computed, reactive, ref } from 'vue';
import { Page } from '@vben/common-ui';
import { useAccessStore, useUserStore } from '@vben/stores';
import {
deleteTeamManager,
pageTeamManager,
} from '#/api/legacy/team';
import AccountInput from '#/components/account-input.vue';
import SysOriginLabel from '#/components/sys-origin-label.vue';
import SysOriginSelect from '#/components/sys-origin-select.vue';
import {
formatDate,
getAllowedSysOrigins,
} from '#/views/system/shared';
import {
Button,
Card,
Modal,
Pagination,
Space,
Table,
message,
} from 'antdv-next';
import TeamManagerFormModal from './components/team-manager-form-modal.vue';
defineOptions({ name: 'TeamManagerList' });
const accessStore = useAccessStore();
const userStore = useUserStore();
const sysOriginOptions = getAllowedSysOrigins(accessStore.accessCodes || []);
const loading = ref(false);
const total = ref(0);
const list = ref<Array<Record<string, any>>>([]);
const formOpen = ref(false);
const activeRow = ref<null | Record<string, any>>(null);
const query = reactive({
createUser: (accessStore.accessCodes || []).includes('team:manager:list:query:all')
? null
: userStore.userInfo?.userId || '',
cursor: 1,
limit: 20,
sysOrigin: sysOriginOptions[0]?.value ?? 'LIKEI',
userId: '',
});
const columns = [
{ dataIndex: 'sysOrigin', key: 'sysOrigin', title: '系统', width: 100 },
{ dataIndex: 'userProfile', key: 'userProfile', title: '经理', width: 240 },
{ dataIndex: 'regionName', key: 'regionName', title: '区域', width: 140 },
{ dataIndex: 'contact', key: 'contact', title: '联系方式', width: 180 },
{ dataIndex: 'createUserName', key: 'createUserName', title: '创建人', width: 140 },
{ dataIndex: 'updateUserName', key: 'updateUserName', title: '修改人', width: 140 },
{ dataIndex: 'createTime', key: 'createTime', title: '创建时间', width: 180 },
{ dataIndex: 'actions', key: 'actions', title: '操作', width: 120 },
];
function hasPermission(code: string) {
const codes = accessStore.accessCodes || [];
return codes.length === 0 || codes.includes(code);
}
const canCreate = computed(() => hasPermission('team:manager:list:add'));
const canEdit = computed(() => hasPermission('team:manager:list:edit'));
const canDelete = computed(() => hasPermission('team:manager:list:del'));
const showOperationCol = computed(() => canEdit.value || canDelete.value);
async function loadData(reset = false) {
if (reset) {
query.cursor = 1;
}
loading.value = true;
try {
const result = await pageTeamManager({ ...query });
list.value = result.records || [];
total.value = result.total || 0;
} finally {
loading.value = false;
}
}
function handleSearch() {
loadData(true);
}
function handlePageChange(page: number, pageSize: number) {
query.cursor = page;
query.limit = pageSize;
loadData();
}
function openCreate() {
activeRow.value = {
sysOrigin: query.sysOrigin,
};
formOpen.value = true;
}
function openEdit(record: Record<string, any>) {
activeRow.value = {
...record,
sysOrigin: record.sysOrigin || query.sysOrigin,
};
formOpen.value = true;
}
function handleDelete(record: Record<string, any>) {
Modal.confirm({
title: '您确定要删除该经理吗?',
async onOk() {
await deleteTeamManager(record.id);
message.success('删除成功');
await loadData(true);
},
});
}
loadData(true);
</script>
<template>
<Page title="经理列表">
<Card>
<div class="toolbar">
<Space wrap>
<SysOriginSelect
v-model:value="query.sysOrigin"
:options="sysOriginOptions"
style="width: 140px"
@change="handleSearch"
/>
<AccountInput
v-model:value="query.userId"
placeholder="经理用户ID"
:sys-origin="query.sysOrigin"
style="width: 220px"
/>
<Button :loading="loading" type="primary" @click="handleSearch">
搜索
</Button>
<Button v-if="canCreate" @click="openCreate">新增经理</Button>
</Space>
</div>
<Table
:columns="showOperationCol ? columns : columns.filter((item) => item.key !== 'actions')"
:data-source="list"
:loading="loading"
:pagination="false"
row-key="id"
>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'sysOrigin'">
<SysOriginLabel :value="record.sysOrigin" />
</template>
<template v-else-if="column.key === 'userProfile'">
<div class="user-cell">
<img
:src="record.userProfile?.userAvatar || 'https://dummyimage.com/44x44/e2e8f0/64748b&text=U'"
alt=""
class="user-avatar"
>
<div class="user-info">
<div class="user-name-row">
<span>{{ record.userProfile?.userNickname || '-' }}</span>
<span class="user-short-id">
短ID{{ record.userProfile?.actualAccount || '-' }}
</span>
</div>
<div class="user-sub">
ID{{ record.userProfile?.id || '-' }}
</div>
</div>
</div>
</template>
<template v-else-if="column.key === 'contact'">
{{ canEdit ? record.contact || '-' : '-' }}
</template>
<template v-else-if="column.key === 'createTime'">
{{ formatDate(record.createTime) }}
</template>
<template v-else-if="column.key === 'actions' && showOperationCol">
<Space wrap>
<Button
v-if="canEdit"
size="small"
type="link"
@click="openEdit(record)"
>
编辑
</Button>
<Button
v-if="canDelete"
danger
size="small"
type="link"
@click="handleDelete(record)"
>
删除
</Button>
</Space>
</template>
</template>
</Table>
<div class="pagination">
<Pagination
:current="query.cursor"
:page-size="query.limit"
:total="total"
show-size-changer
@change="handlePageChange"
@showSizeChange="handlePageChange"
/>
</div>
</Card>
<TeamManagerFormModal
:open="formOpen"
:row="activeRow"
:sys-origin="query.sysOrigin"
@close="formOpen = false"
@success="loadData(true)"
/>
</Page>
</template>
<style scoped>
.toolbar {
margin-bottom: 16px;
}
.user-cell {
align-items: center;
display: flex;
gap: 10px;
}
.user-avatar {
border-radius: 999px;
height: 44px;
object-fit: cover;
width: 44px;
}
.user-name-row {
align-items: center;
display: flex;
flex-wrap: wrap;
gap: 6px;
}
.user-short-id {
color: #64748b;
font-size: 12px;
}
.user-sub {
color: #64748b;
margin-top: 4px;
}
.pagination {
display: flex;
justify-content: flex-end;
margin-top: 16px;
}
</style>