2025-06-20 11:24:33 +08:00
|
|
|
|
<template>
|
2025-07-01 17:28:18 +08:00
|
|
|
|
<div class="bg-#fff rounded-8px border-1px border-#D7D7D9 border-solid w-100% py-0 px-20px mt-24px pb-24px">
|
|
|
|
|
|
<div class="title-row">
|
|
|
|
|
|
<span class="title">账号管理</span>
|
2025-06-20 11:24:33 +08:00
|
|
|
|
<a-button type="outline" class="add-account-button" @click="handleAddAccount">添加子账号</a-button>
|
2025-07-01 17:28:18 +08:00
|
|
|
|
</div>
|
2025-06-20 11:24:33 +08:00
|
|
|
|
<a-table
|
|
|
|
|
|
:columns="columns"
|
|
|
|
|
|
:data="data"
|
|
|
|
|
|
:pagination="pagination"
|
2025-07-01 17:28:18 +08:00
|
|
|
|
class="mt-8px h-540px"
|
2025-06-20 11:24:33 +08:00
|
|
|
|
@page-change="handlePageChange"
|
|
|
|
|
|
@page-size-change="handlePageSizeChange"
|
|
|
|
|
|
>
|
2025-07-01 17:28:18 +08:00
|
|
|
|
<template #empty>
|
|
|
|
|
|
<NoData />
|
|
|
|
|
|
</template>
|
2025-06-20 11:24:33 +08:00
|
|
|
|
<template #mobile="{ record }">
|
|
|
|
|
|
<div class="flex item-center pt-13px pb-13px">
|
|
|
|
|
|
<span class="mr-4px">{{ record.mobile }}</span>
|
|
|
|
|
|
<a-tag v-if="record.type === 0" class="primary-account">主账号</a-tag>
|
|
|
|
|
|
<a-tag v-else class="sub-account">子账号</a-tag>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
<template #action="{ record }">
|
|
|
|
|
|
<a-button
|
|
|
|
|
|
v-if="record.type !== 0"
|
|
|
|
|
|
class="delete-button"
|
|
|
|
|
|
size="mini"
|
|
|
|
|
|
type="outline"
|
|
|
|
|
|
status="danger"
|
|
|
|
|
|
@click="openDeleteModal(record)"
|
|
|
|
|
|
>
|
|
|
|
|
|
删除
|
|
|
|
|
|
</a-button>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</a-table>
|
|
|
|
|
|
<Modal v-model:visible="addAccountVisible" width="480px" title="添加子账号" :okText="okText" @ok="handleOk">
|
|
|
|
|
|
<div v-if="canAddAccount" class="add-account-container">
|
|
|
|
|
|
<h2 class="add-account-title">生成企业专属链接,成员通过访问即可注册并加入企业账号。</h2>
|
|
|
|
|
|
<p class="add-account-subtitle">子账号可独立登录,权限继承主账号配置。</p>
|
|
|
|
|
|
<div class="add-account-body">
|
|
|
|
|
|
<p>用该链接加入企业吧!</p>
|
|
|
|
|
|
<p>{{ inviteUrl }}</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div v-else class="add-account-container">
|
|
|
|
|
|
<h2 class="cannot-add-account-title flex item-center">
|
2025-06-23 01:46:41 -04:00
|
|
|
|
<img src="@/assets/warning.svg" alt="" />
|
2025-06-20 11:24:33 +08:00
|
|
|
|
当前可用子账号数为0。
|
|
|
|
|
|
</h2>
|
|
|
|
|
|
<p class="cannot-add-account-subtitle">如需添加更多子账号,您可联系销售人员进行购买和权限扩展。</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</Modal>
|
|
|
|
|
|
<CustomerServiceModal v-model:visible="customerServiceVisible" />
|
|
|
|
|
|
<DeleteModal v-model:visible="deleteVisible" :title="deleteTitle" @ok="handleDelete">
|
|
|
|
|
|
<p class="delete-modal-content">删除后,该账号将无法登录您的企业。</p>
|
|
|
|
|
|
</DeleteModal>
|
2025-07-01 17:28:18 +08:00
|
|
|
|
</div>
|
2025-06-20 11:24:33 +08:00
|
|
|
|
</template>
|
|
|
|
|
|
<script setup lang="ts">
|
|
|
|
|
|
import Container from '@/components/container.vue';
|
|
|
|
|
|
import { ref, onMounted, reactive, computed } from 'vue';
|
|
|
|
|
|
import { fetchSubAccountPage, removeEnterpriseAccount, getEnterpriseInviteCode } from '@/api/all';
|
|
|
|
|
|
import Modal from '@/components/modal.vue';
|
|
|
|
|
|
import DeleteModal from '@/components/delete-modal.vue';
|
|
|
|
|
|
import CustomerServiceModal from '@/components/customer-service-modal.vue';
|
2025-06-20 16:16:17 +08:00
|
|
|
|
import { useClipboard } from '@vueuse/core';
|
|
|
|
|
|
import { useEnterpriseStore } from '@/stores/modules/enterprise';
|
2025-06-20 11:24:33 +08:00
|
|
|
|
|
2025-06-20 16:16:17 +08:00
|
|
|
|
const store = useEnterpriseStore();
|
2025-06-20 11:24:33 +08:00
|
|
|
|
const columns = [
|
|
|
|
|
|
{
|
|
|
|
|
|
title: '手机号',
|
|
|
|
|
|
slotName: 'mobile',
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
title: '操作',
|
|
|
|
|
|
slotName: 'action',
|
|
|
|
|
|
},
|
|
|
|
|
|
];
|
|
|
|
|
|
const data = ref([]);
|
|
|
|
|
|
const pagination = reactive({
|
|
|
|
|
|
total: 0,
|
|
|
|
|
|
showPageSize: true,
|
|
|
|
|
|
showTotal: true,
|
|
|
|
|
|
defaultCurrent: 1,
|
|
|
|
|
|
defaultPageSize: 10,
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
const params = reactive({
|
|
|
|
|
|
page_size: 10,
|
|
|
|
|
|
page: 1,
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
const inviteUrl = ref('');
|
|
|
|
|
|
|
|
|
|
|
|
const addAccountVisible = ref(false);
|
|
|
|
|
|
const deleteVisible = ref(false);
|
|
|
|
|
|
const deleteTitle = ref('');
|
|
|
|
|
|
|
2025-06-20 16:16:17 +08:00
|
|
|
|
const enterpriseInfo = store.getEnterpriseInfo();
|
2025-06-20 11:24:33 +08:00
|
|
|
|
|
|
|
|
|
|
const okText = computed(() => {
|
|
|
|
|
|
if (!canAddAccount.value) {
|
|
|
|
|
|
return '联系客服';
|
|
|
|
|
|
}
|
|
|
|
|
|
return '复制邀请链接';
|
|
|
|
|
|
});
|
|
|
|
|
|
const customerServiceVisible = ref(false);
|
|
|
|
|
|
const canAddAccount = computed(() => {
|
2025-06-23 22:03:57 -04:00
|
|
|
|
if (!enterpriseInfo) return false;
|
|
|
|
|
|
|
2025-06-20 11:24:33 +08:00
|
|
|
|
return enterpriseInfo.sub_account_quota > enterpriseInfo.used_sub_account_count;
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
const currentSelectAccount = ref();
|
|
|
|
|
|
|
|
|
|
|
|
const { copy, copied, isSupported } = useClipboard({ source: inviteUrl });
|
|
|
|
|
|
|
|
|
|
|
|
function handlePageChange(current: number) {
|
|
|
|
|
|
params.page = current;
|
|
|
|
|
|
getSubAccount();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function handlePageSizeChange(pageSize: number) {
|
|
|
|
|
|
params.page_size = pageSize;
|
|
|
|
|
|
getSubAccount();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async function getSubAccount() {
|
|
|
|
|
|
const res = await fetchSubAccountPage(params);
|
2025-06-23 22:03:57 -04:00
|
|
|
|
const { data, total, code } = res.data;
|
|
|
|
|
|
if (code === 200) {
|
|
|
|
|
|
pagination.total = total;
|
|
|
|
|
|
data.value = data;
|
|
|
|
|
|
}
|
2025-06-20 11:24:33 +08:00
|
|
|
|
}
|
|
|
|
|
|
async function handleAddAccount() {
|
|
|
|
|
|
if (canAddAccount.value) {
|
|
|
|
|
|
const res = await getEnterpriseInviteCode();
|
|
|
|
|
|
const port = window.location.port === '' ? '' : ':' + window.location.port;
|
|
|
|
|
|
const domain = window.location.protocol + '//' + window.location.hostname + port;
|
2025-06-23 01:46:41 -04:00
|
|
|
|
|
|
|
|
|
|
inviteUrl.value = domain + '?invite_code=' + res.data?.invite_code;
|
2025-06-20 11:24:33 +08:00
|
|
|
|
}
|
|
|
|
|
|
addAccountVisible.value = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function handleOk() {
|
|
|
|
|
|
if (!canAddAccount.value) {
|
|
|
|
|
|
customerServiceVisible.value = true;
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (!isSupported) {
|
|
|
|
|
|
AMessage.error('您的浏览器不支持复制,请手动复制!');
|
|
|
|
|
|
}
|
|
|
|
|
|
copy(inviteUrl.value);
|
|
|
|
|
|
if (!copied) {
|
|
|
|
|
|
AMessage.error('复制失败,请手动复制!');
|
|
|
|
|
|
}
|
|
|
|
|
|
AMessage.success('复制成功!');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function openDeleteModal(record: { id: number; mobile: string }) {
|
|
|
|
|
|
currentSelectAccount.value = record;
|
|
|
|
|
|
deleteTitle.value = `确认删除“${record.mobile}”子账号吗?`;
|
|
|
|
|
|
deleteVisible.value = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async function handleDelete() {
|
|
|
|
|
|
await removeEnterpriseAccount(currentSelectAccount.value.id);
|
|
|
|
|
|
AMessage.success('移除成功!');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
onMounted(() => {
|
|
|
|
|
|
getSubAccount();
|
|
|
|
|
|
});
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style scoped lang="less">
|
|
|
|
|
|
.primary-account {
|
|
|
|
|
|
border-radius: 2px;
|
|
|
|
|
|
padding-right: 8px;
|
|
|
|
|
|
padding-left: 8px;
|
|
|
|
|
|
background: var(--Brand-Brand-1, rgba(240, 237, 255, 1));
|
2025-07-01 14:34:16 +08:00
|
|
|
|
font-family: 'PuHuiTi-Medium';
|
2025-06-20 11:24:33 +08:00
|
|
|
|
font-weight: 400;
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
line-height: 20px;
|
|
|
|
|
|
color: var(--Brand-Brand-6, rgba(109, 76, 254, 1));
|
|
|
|
|
|
}
|
|
|
|
|
|
.sub-account {
|
|
|
|
|
|
border-radius: 2px;
|
|
|
|
|
|
padding-right: 8px;
|
|
|
|
|
|
padding-left: 8px;
|
|
|
|
|
|
background: var(--Functional-Warning-1, rgba(255, 245, 222, 1));
|
2025-07-01 14:34:16 +08:00
|
|
|
|
font-family: 'PuHuiTi-Medium';
|
2025-06-20 11:24:33 +08:00
|
|
|
|
font-weight: 400;
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
color: var(--Functional-Warning-6, rgba(255, 174, 0, 1));
|
|
|
|
|
|
}
|
|
|
|
|
|
.delete-button {
|
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
|
padding: 2px 12px;
|
|
|
|
|
|
border: 1px solid var(--Functional-Danger-6, rgba(246, 75, 49, 1));
|
2025-07-01 14:34:16 +08:00
|
|
|
|
font-family: 'PuHuiTi-Medium';
|
2025-06-20 11:24:33 +08:00
|
|
|
|
font-weight: 400;
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
line-height: 20px;
|
|
|
|
|
|
color: var(--Functional-Danger-6, rgba(246, 75, 49, 1));
|
|
|
|
|
|
}
|
|
|
|
|
|
.add-account-button {
|
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
|
padding: 5px 16px;
|
|
|
|
|
|
border: 1px solid var(--Brand-Brand-6, rgba(109, 76, 254, 1));
|
2025-07-01 14:34:16 +08:00
|
|
|
|
font-family: 'PuHuiTi-Medium';
|
2025-06-20 11:24:33 +08:00
|
|
|
|
font-weight: 400;
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
color: var(--Brand-Brand-6, rgba(109, 76, 254, 1));
|
|
|
|
|
|
}
|
|
|
|
|
|
.add-account-container {
|
|
|
|
|
|
margin-top: 13px;
|
|
|
|
|
|
margin-bottom: 12px;
|
|
|
|
|
|
.add-account-title {
|
|
|
|
|
|
margin: 0;
|
2025-07-01 14:34:16 +08:00
|
|
|
|
font-family: 'PuHuiTi-Medium';
|
2025-06-20 11:24:33 +08:00
|
|
|
|
font-weight: 400;
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
color: var(--Text-1, rgba(33, 31, 36, 1));
|
|
|
|
|
|
}
|
|
|
|
|
|
.add-account-subtitle {
|
|
|
|
|
|
margin: 4px 0 0 0;
|
2025-07-01 14:34:16 +08:00
|
|
|
|
font-family: 'PuHuiTi-Medium';
|
2025-06-20 11:24:33 +08:00
|
|
|
|
font-weight: 400;
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
color: var(--Text-2, rgba(60, 64, 67, 1));
|
|
|
|
|
|
}
|
|
|
|
|
|
.add-account-body {
|
|
|
|
|
|
margin-top: 16px;
|
|
|
|
|
|
width: 432px;
|
|
|
|
|
|
height: 84px;
|
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
|
padding: 12px 16px;
|
|
|
|
|
|
background: var(--BG-200, rgba(242, 243, 245, 1));
|
2025-07-01 14:34:16 +08:00
|
|
|
|
font-family: 'PuHuiTi-Medium';
|
2025-06-20 11:24:33 +08:00
|
|
|
|
font-weight: 400;
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
color: var(--Text-2, rgba(60, 64, 67, 1));
|
|
|
|
|
|
p {
|
|
|
|
|
|
padding: 0;
|
|
|
|
|
|
margin: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
.cannot-add-account-title {
|
|
|
|
|
|
margin: 0;
|
2025-07-01 14:34:16 +08:00
|
|
|
|
font-family: 'PuHuiTi-Medium';
|
2025-06-20 11:24:33 +08:00
|
|
|
|
font-weight: 400;
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
color: var(--Text-1, rgba(33, 31, 36, 1));
|
|
|
|
|
|
img {
|
|
|
|
|
|
width: 20px;
|
|
|
|
|
|
height: 20px;
|
|
|
|
|
|
margin-right: 12px;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
.cannot-add-account-subtitle {
|
|
|
|
|
|
margin: 16px 0 0 0;
|
|
|
|
|
|
padding-left: 32px;
|
2025-07-01 14:34:16 +08:00
|
|
|
|
font-family: 'PuHuiTi-Medium';
|
2025-06-20 11:24:33 +08:00
|
|
|
|
font-weight: 400;
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
color: var(--Text-2, rgba(60, 64, 67, 1));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
.delete-modal-content {
|
|
|
|
|
|
margin-left: 34px;
|
|
|
|
|
|
margin-top: 16px;
|
2025-07-01 14:34:16 +08:00
|
|
|
|
font-family: 'PuHuiTi-Medium';
|
2025-06-20 11:24:33 +08:00
|
|
|
|
font-weight: 400;
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
color: var(--Text-2, rgba(60, 64, 67, 1));
|
|
|
|
|
|
}
|
2025-07-01 17:28:18 +08:00
|
|
|
|
.title-row {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
height: 64px;
|
|
|
|
|
|
padding: 10px 0 2px 0;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
.title {
|
|
|
|
|
|
color: var(--Text-1, #211f24);
|
|
|
|
|
|
font-family: 'PuHuiTi-Medium';
|
|
|
|
|
|
font-size: 18px;
|
|
|
|
|
|
font-style: normal;
|
|
|
|
|
|
font-weight: 400;
|
|
|
|
|
|
line-height: 24px; /* 150% */
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-06-20 11:24:33 +08:00
|
|
|
|
</style>
|