update user page style
This commit is contained in:
@@ -28,7 +28,11 @@
|
|||||||
<telephone-link :value="managedUser.user.phoneNo" placeholder="未填写" />
|
<telephone-link :value="managedUser.user.phoneNo" placeholder="未填写" />
|
||||||
</template>
|
</template>
|
||||||
</t-cell>
|
</t-cell>
|
||||||
<t-cell title="上次登录时间" :note="Time.toPassedDateTime(managedUser.user.lastLoginAt)" />
|
<t-cell title="上次登录时间">
|
||||||
|
<template #note>
|
||||||
|
<pass-time-label :timestamp="managedUser.user.lastLoginAt" underline />
|
||||||
|
</template>
|
||||||
|
</t-cell>
|
||||||
</t-cell-group>
|
</t-cell-group>
|
||||||
|
|
||||||
<t-cell-group v-if="currentUser" theme="card">
|
<t-cell-group v-if="currentUser" theme="card">
|
||||||
@@ -46,33 +50,23 @@
|
|||||||
</t-cell>
|
</t-cell>
|
||||||
</t-cell-group>
|
</t-cell-group>
|
||||||
|
|
||||||
<section v-if="currentUser" class="registration-actions bg-white">
|
<t-cell-group v-if="currentUser" title="可登记事件" theme="card">
|
||||||
<header>
|
<t-cell v-for="item in scopeList" :key="item.id" :title="item.name"/>
|
||||||
<h4 class="title">可登记事件</h4>
|
<t-cell v-if="!scopeList.length" title="未配置" />
|
||||||
</header>
|
</t-cell-group>
|
||||||
<div class="actions">
|
|
||||||
<t-tag
|
|
||||||
v-for="item in scopeList"
|
|
||||||
:key="item"
|
|
||||||
variant="light-outline"
|
|
||||||
theme="success"
|
|
||||||
:content="item"
|
|
||||||
/>
|
|
||||||
<div v-if="!scopeList.length" class="empty-card">未配置</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
<t-button v-can="permissionCodes.user.update" class="edit" theme="primary" @click="toEdit">编辑用户</t-button>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { Toast } from "tdesign-mobile-vue";
|
import { Toast } from "tdesign-mobile-vue";
|
||||||
import { Time, type User, UserAPI } from "timi-web";
|
import { PassTimeLabel, type User, UserAPI } from "timi-web";
|
||||||
import EventAPI from "@/api/EventAPI";
|
import EventAPI from "@/api/EventAPI";
|
||||||
import ManagedUserAPI from "@/api/ManagedUserAPI";
|
import ManagedUserAPI from "@/api/ManagedUserAPI";
|
||||||
import type { ManagedUser } from "@/types/ManagedUser";
|
import type { ManagedUser } from "@/types/ManagedUser";
|
||||||
import type { EventItem } from "@/types/EventItem";
|
import type { EventItem } from "@/types/EventItem";
|
||||||
import { usePermissionSettingsStore } from "@/store/permissionSettingsStore";
|
import { usePermissionSettingsStore } from "@/store/permissionSettingsStore";
|
||||||
|
import { useNavBarStore } from "@/store/navBarStore";
|
||||||
|
import { useUserStore } from "timi-web";
|
||||||
import { buildFallbackAvatar } from "@/utils/avatar";
|
import { buildFallbackAvatar } from "@/utils/avatar";
|
||||||
import { buildEffectiveRoleCodeSet, getManagedUserRoleList, getRoleDisplayName } from "@/utils/role";
|
import { buildEffectiveRoleCodeSet, getManagedUserRoleList, getRoleDisplayName } from "@/utils/role";
|
||||||
import { permissionCodes } from "@/utils/permission";
|
import { permissionCodes } from "@/utils/permission";
|
||||||
@@ -83,6 +77,8 @@ defineOptions({
|
|||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
const navBarStore = useNavBarStore();
|
||||||
|
const userStore = useUserStore();
|
||||||
const permissionStore = usePermissionSettingsStore();
|
const permissionStore = usePermissionSettingsStore();
|
||||||
|
|
||||||
// ---------- 用户数据 ----------
|
// ---------- 用户数据 ----------
|
||||||
@@ -110,9 +106,7 @@ const scopeList = computed(() => {
|
|||||||
if (!item) {
|
if (!item) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
return eventList.value
|
return eventList.value.filter(action => canEventItem(action, item));
|
||||||
.filter(action => canEventItem(action, item))
|
|
||||||
.map(item => item.name);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// ---------- 导航 ----------
|
// ---------- 导航 ----------
|
||||||
@@ -146,7 +140,7 @@ function isUser(user?: Partial<User>): user is User {
|
|||||||
// ---------- 事件范围 ----------
|
// ---------- 事件范围 ----------
|
||||||
|
|
||||||
function canEventItem(action: EventItem, item: ManagedUser): boolean {
|
function canEventItem(action: EventItem, item: ManagedUser): boolean {
|
||||||
const userRoleCodeSet = buildEffectiveRoleCodeSet(item);
|
const userRoleCodeSet = buildEffectiveRoleCodeSet(item, permissionStore.roleList);
|
||||||
const roleCodeList = action.roleCodeList || [];
|
const roleCodeList = action.roleCodeList || [];
|
||||||
if (!roleCodeList.length) {
|
if (!roleCodeList.length) {
|
||||||
return false;
|
return false;
|
||||||
@@ -158,22 +152,45 @@ function canEventItem(action: EventItem, item: ManagedUser): boolean {
|
|||||||
|
|
||||||
async function loadData(): Promise<void> {
|
async function loadData(): Promise<void> {
|
||||||
const routeId = String(route.params.id || "");
|
const routeId = String(route.params.id || "");
|
||||||
const [detail, actions] = await Promise.all([
|
const [detail] = await Promise.all([
|
||||||
ManagedUserAPI.detail(routeId),
|
ManagedUserAPI.detail(routeId),
|
||||||
EventAPI.listValid(),
|
|
||||||
permissionStore.loadAll()
|
permissionStore.loadAll()
|
||||||
]);
|
]);
|
||||||
managedUser.value = detail;
|
managedUser.value = detail;
|
||||||
eventList.value = actions || [];
|
if (!userStore.hasPermissions(permissionCodes.event.read)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await EventAPI.list({ index: 0, size: 1000 }, { storeId: detail.storeId });
|
||||||
|
eventList.value = (result.list || []).filter(isValidEvent);
|
||||||
|
} catch {
|
||||||
|
eventList.value = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function isValidEvent(event: EventItem): boolean {
|
||||||
|
if (event.status !== "ACTIVE") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const now = Date.now();
|
||||||
|
return (event.beginAt === undefined || event.beginAt <= now)
|
||||||
|
&& (event.endAt === undefined || now <= event.endAt);
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
try {
|
try {
|
||||||
await loadData();
|
await loadData();
|
||||||
|
if (userStore.hasPermissions(permissionCodes.user.update)) {
|
||||||
|
navBarStore.setRightText("编辑", "var(--td-brand-color)", toEdit);
|
||||||
|
}
|
||||||
} catch {
|
} catch {
|
||||||
Toast.error("用户详情加载失败");
|
Toast.error("用户详情加载失败");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
onUnmounted(() => navBarStore.clearRight());
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
@@ -189,34 +206,6 @@ onMounted(async () => {
|
|||||||
border-radius: .875rem;
|
border-radius: .875rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.registration-actions {
|
|
||||||
gap: .5rem;
|
|
||||||
margin: 0 1rem;
|
|
||||||
padding: 1rem;
|
|
||||||
display: flex;
|
|
||||||
border-radius: 1rem;
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
.title {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.actions {
|
|
||||||
gap: .5rem;
|
|
||||||
display: flex;
|
|
||||||
|
|
||||||
.empty-card {
|
|
||||||
color: #52607a;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.edit {
|
|
||||||
left: 1rem;
|
|
||||||
right: 1rem;
|
|
||||||
bottom: calc(.75rem + env(safe-area-inset-bottom, 0));
|
|
||||||
position: fixed;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
:global(html.theme-dark) {
|
:global(html.theme-dark) {
|
||||||
@@ -229,10 +218,6 @@ onMounted(async () => {
|
|||||||
|
|
||||||
p,
|
p,
|
||||||
.info-list li span,
|
.info-list li span,
|
||||||
.empty-card {
|
|
||||||
color: #94a3b8;
|
|
||||||
}
|
|
||||||
|
|
||||||
.action {
|
.action {
|
||||||
color: #e2e8f0;
|
color: #e2e8f0;
|
||||||
background: rgba(15, 23, 42, .72);
|
background: rgba(15, 23, 42, .72);
|
||||||
|
|||||||
@@ -14,7 +14,6 @@
|
|||||||
<div class="picker-text" v-text="selectedStoreName" />
|
<div class="picker-text" v-text="selectedStoreName" />
|
||||||
</t-form-item>
|
</t-form-item>
|
||||||
</t-form>
|
</t-form>
|
||||||
<t-button class="save" theme="primary" :loading="isSaving" @click="saveUser">保存</t-button>
|
|
||||||
</div>
|
</div>
|
||||||
<t-popup v-model="storePickerVisible" placement="bottom">
|
<t-popup v-model="storePickerVisible" placement="bottom">
|
||||||
<t-picker
|
<t-picker
|
||||||
@@ -32,6 +31,7 @@ import { Toast } from "tdesign-mobile-vue";
|
|||||||
import { useUserStore } from "timi-web";
|
import { useUserStore } from "timi-web";
|
||||||
import ManagedUserAPI from "@/api/ManagedUserAPI";
|
import ManagedUserAPI from "@/api/ManagedUserAPI";
|
||||||
import { useCurrentStoreStore } from "@/store/currentStoreStore";
|
import { useCurrentStoreStore } from "@/store/currentStoreStore";
|
||||||
|
import { useNavBarStore } from "@/store/navBarStore";
|
||||||
import type { ManagedUser } from "@/types/ManagedUser";
|
import type { ManagedUser } from "@/types/ManagedUser";
|
||||||
import { gaoRoleCodes, permissionCodes } from "@/utils/permission";
|
import { gaoRoleCodes, permissionCodes } from "@/utils/permission";
|
||||||
|
|
||||||
@@ -43,6 +43,7 @@ defineOptions({
|
|||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
const navBarStore = useNavBarStore();
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const currentStoreStore = useCurrentStoreStore();
|
const currentStoreStore = useCurrentStoreStore();
|
||||||
|
|
||||||
@@ -205,12 +206,17 @@ function validateForm(): boolean {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
|
if (userStore.hasPermissions(savePermissionCode.value)) {
|
||||||
|
navBarStore.setRightText("保存", "var(--td-brand-color)", saveUser);
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
await fillForm();
|
await fillForm();
|
||||||
} catch {
|
} catch {
|
||||||
Toast.error("用户数据加载失败");
|
Toast.error("用户数据加载失败");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
onUnmounted(() => navBarStore.clearRight());
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
@@ -225,12 +231,6 @@ onMounted(async () => {
|
|||||||
color: var(--td-text-color-primary);
|
color: var(--td-text-color-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.save {
|
|
||||||
left: 1rem;
|
|
||||||
right: 1rem;
|
|
||||||
bottom: calc(.75rem + env(safe-area-inset-bottom, 0));
|
|
||||||
position: fixed;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
:global(html.theme-dark) {
|
:global(html.theme-dark) {
|
||||||
|
|||||||
@@ -25,11 +25,13 @@ const code = String(route.query.code || "");
|
|||||||
const expireAt = Number(route.query.expireAt || 0);
|
const expireAt = Number(route.query.expireAt || 0);
|
||||||
const storeName = String(route.query.storeName || "");
|
const storeName = String(route.query.storeName || "");
|
||||||
const roleName = String(route.query.roleName || "");
|
const roleName = String(route.query.roleName || "");
|
||||||
|
const inviterName = String(route.query.inviterName || "未命名用户");
|
||||||
const registerLink = `${window.location.origin}/gao/invite/register?code=${encodeURIComponent(code)}`;
|
const registerLink = `${window.location.origin}/gao/invite/register?code=${encodeURIComponent(code)}`;
|
||||||
const posterOptions = computed(() => ({
|
const posterOptions = computed(() => ({
|
||||||
code: registerLink,
|
code: registerLink,
|
||||||
storeName,
|
storeName,
|
||||||
roleName,
|
roleName,
|
||||||
|
inviterName,
|
||||||
expireAt
|
expireAt
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,6 @@
|
|||||||
class="item"
|
class="item"
|
||||||
v-for="item in pageResult.list"
|
v-for="item in pageResult.list"
|
||||||
:key="item.id"
|
:key="item.id"
|
||||||
:description="`可登记事件:${getActionScope(item)}`"
|
|
||||||
arrow
|
arrow
|
||||||
@click="toDetail(item)"
|
@click="toDetail(item)"
|
||||||
>
|
>
|
||||||
@@ -38,14 +37,17 @@
|
|||||||
<t-tag class="meta" size="small" theme="success" variant="outline" :content="getRoleName(item)" />
|
<t-tag class="meta" size="small" theme="success" variant="outline" :content="getRoleName(item)" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
<template #description>
|
||||||
|
<telephone-link :value="item.user?.phoneNo" />
|
||||||
|
</template>
|
||||||
</t-cell>
|
</t-cell>
|
||||||
</t-cell-group>
|
</t-cell-group>
|
||||||
<div v-if="!pageResult.list.length" class="load-state" v-text="isLoading ? '正在加载用户' : '暂无用户'" />
|
<div v-if="!pageResult.list.length" class="load-state" v-text="isLoading ? '正在加载用户' : '暂无用户'" />
|
||||||
<div v-if="pageResult.list.length" class="load-state" v-text="isNoMore ? '已经到底了' : '上拉加载更多'" />
|
<div v-if="pageResult.list.length" class="load-state" v-text="isNoMore ? '已经到底了' : '上拉加载更多'" />
|
||||||
</t-pull-down-refresh>
|
</t-pull-down-refresh>
|
||||||
<div class="actions">
|
<div class="actions">
|
||||||
|
<t-button v-can="permissionCodes.user.create" theme="light" type="button" @click="toCreate">新增用户</t-button>
|
||||||
<t-button v-can="permissionCodes.user.create" theme="primary" type="button" @click="inviteVisible = true">邀请注册</t-button>
|
<t-button v-can="permissionCodes.user.create" theme="primary" type="button" @click="inviteVisible = true">邀请注册</t-button>
|
||||||
<t-button v-can="permissionCodes.user.create" theme="primary" type="button" @click="toCreate">新增用户</t-button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<user-invite v-model:visible="inviteVisible" :store-id="selectedStoreId === allStoreFilterValue ? undefined : selectedStoreId" />
|
<user-invite v-model:visible="inviteVisible" :store-id="selectedStoreId === allStoreFilterValue ? undefined : selectedStoreId" />
|
||||||
@@ -54,14 +56,12 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { Toast, type DropdownValue } from "tdesign-mobile-vue";
|
import { Toast, type DropdownValue } from "tdesign-mobile-vue";
|
||||||
import { type Page, type PageResult, UserAPI, type User, useUserStore } from "timi-web";
|
import { type Page, type PageResult, UserAPI, type User, useUserStore } from "timi-web";
|
||||||
import EventAPI from "@/api/EventAPI";
|
|
||||||
import ManagedUserAPI from "@/api/ManagedUserAPI";
|
import ManagedUserAPI from "@/api/ManagedUserAPI";
|
||||||
import { useCurrentStoreStore } from "@/store/currentStoreStore";
|
import { useCurrentStoreStore } from "@/store/currentStoreStore";
|
||||||
import type { ManagedUser } from "@/types/ManagedUser";
|
import type { ManagedUser } from "@/types/ManagedUser";
|
||||||
import type { EventItem } from "@/types/EventItem";
|
|
||||||
import { usePermissionSettingsStore } from "@/store/permissionSettingsStore";
|
import { usePermissionSettingsStore } from "@/store/permissionSettingsStore";
|
||||||
import { buildFallbackAvatar } from "@/utils/avatar";
|
import { buildFallbackAvatar } from "@/utils/avatar";
|
||||||
import { buildEffectiveRoleCodeSet, getManagedUserRoleList, getRoleDisplayName } from "@/utils/role";
|
import { getManagedUserRoleList, getRoleDisplayName } from "@/utils/role";
|
||||||
import { gaoRoleCodes, permissionCodes } from "@/utils/permission";
|
import { gaoRoleCodes, permissionCodes } from "@/utils/permission";
|
||||||
import UserInvite from "@/pages/user/component/UserInvite.vue";
|
import UserInvite from "@/pages/user/component/UserInvite.vue";
|
||||||
|
|
||||||
@@ -103,7 +103,6 @@ const userListOptions = computed(() => {
|
|||||||
|
|
||||||
// ---------- 列表数据 ----------
|
// ---------- 列表数据 ----------
|
||||||
|
|
||||||
const eventList = ref<EventItem[]>([]);
|
|
||||||
const isRefreshing = ref(false);
|
const isRefreshing = ref(false);
|
||||||
const isLoading = ref(false);
|
const isLoading = ref(false);
|
||||||
const isNoMore = ref(false);
|
const isNoMore = ref(false);
|
||||||
@@ -126,24 +125,6 @@ function getRoleName(item: ManagedUser): string {
|
|||||||
return getRoleDisplayName(getManagedUserRoleList(item)[0], permissionStore.roleList);
|
return getRoleDisplayName(getManagedUserRoleList(item)[0], permissionStore.roleList);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getActionScope(item: ManagedUser): string {
|
|
||||||
const nameList = eventList.value
|
|
||||||
.filter(action => canEventItem(action, item))
|
|
||||||
.map(action => action.name);
|
|
||||||
return nameList.join("、") || "未配置";
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------- 事件范围 ----------
|
|
||||||
|
|
||||||
function canEventItem(action: EventItem, item: ManagedUser): boolean {
|
|
||||||
const userRoleCodeSet = buildEffectiveRoleCodeSet(item);
|
|
||||||
const roleCodeList = action.roleCodeList || [];
|
|
||||||
if (!roleCodeList.length) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return roleCodeList.some(code => userRoleCodeSet.has(code));
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------- 头像 ----------
|
// ---------- 头像 ----------
|
||||||
|
|
||||||
function buildUserAvatar(item: ManagedUser): string {
|
function buildUserAvatar(item: ManagedUser): string {
|
||||||
@@ -168,16 +149,14 @@ async function loadStoreScope(): Promise<void> {
|
|||||||
|
|
||||||
async function loadData(): Promise<void> {
|
async function loadData(): Promise<void> {
|
||||||
await loadStoreScope();
|
await loadStoreScope();
|
||||||
const [userResult, actions] = await Promise.all([
|
const [userResult] = await Promise.all([
|
||||||
ManagedUserAPI.list(page, userListOptions.value),
|
ManagedUserAPI.list(page, userListOptions.value),
|
||||||
EventAPI.listValid(),
|
|
||||||
permissionStore.loadAll()
|
permissionStore.loadAll()
|
||||||
]);
|
]);
|
||||||
pageResult.total = userResult.total;
|
pageResult.total = userResult.total;
|
||||||
pageResult.list = userResult.list || [];
|
pageResult.list = userResult.list || [];
|
||||||
page.index = 1;
|
page.index = 1;
|
||||||
isNoMore.value = pageResult.list.length >= pageResult.total || pageResult.list.length < page.size;
|
isNoMore.value = pageResult.list.length >= pageResult.total || pageResult.list.length < page.size;
|
||||||
eventList.value = actions || [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function refresh(): Promise<void> {
|
async function refresh(): Promise<void> {
|
||||||
|
|||||||
@@ -34,15 +34,6 @@
|
|||||||
</t-cell>
|
</t-cell>
|
||||||
</t-cell-group>
|
</t-cell-group>
|
||||||
<t-empty v-else-if="!isLoading" description="暂无可授权角色" />
|
<t-empty v-else-if="!isLoading" description="暂无可授权角色" />
|
||||||
<t-button
|
|
||||||
v-can="userRoleWriteAccess"
|
|
||||||
class="save"
|
|
||||||
theme="primary"
|
|
||||||
:loading="isSaving"
|
|
||||||
@click="saveRoleList"
|
|
||||||
>
|
|
||||||
保存授权
|
|
||||||
</t-button>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -52,6 +43,7 @@ import { Toast } from "tdesign-mobile-vue";
|
|||||||
import { RoleAPI, type ModuleCode, type Role as UserRole, useUserStore } from "timi-web";
|
import { RoleAPI, type ModuleCode, type Role as UserRole, useUserStore } from "timi-web";
|
||||||
import ManagedUserAPI from "@/api/ManagedUserAPI";
|
import ManagedUserAPI from "@/api/ManagedUserAPI";
|
||||||
import { useCurrentStoreStore } from "@/store/currentStoreStore";
|
import { useCurrentStoreStore } from "@/store/currentStoreStore";
|
||||||
|
import { useNavBarStore } from "@/store/navBarStore";
|
||||||
import type { Role } from "@/store/permissionSettingsStore";
|
import type { Role } from "@/store/permissionSettingsStore";
|
||||||
import type { ManagedUser } from "@/types/ManagedUser";
|
import type { ManagedUser } from "@/types/ManagedUser";
|
||||||
import { getErrorMessage } from "@/utils/error";
|
import { getErrorMessage } from "@/utils/error";
|
||||||
@@ -62,6 +54,7 @@ defineOptions({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
const navBarStore = useNavBarStore();
|
||||||
const moduleCode: ModuleCode = "GAO";
|
const moduleCode: ModuleCode = "GAO";
|
||||||
const allStoreFilterValue = "__ALL_STORES__";
|
const allStoreFilterValue = "__ALL_STORES__";
|
||||||
|
|
||||||
@@ -283,12 +276,20 @@ function setRoleChecked(roleId: string, value: boolean): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
|
if (
|
||||||
|
userStore.hasPermissions(corePermissionCodes.userRole.create)
|
||||||
|
&& userStore.hasPermissions(corePermissionCodes.userRole.delete)
|
||||||
|
) {
|
||||||
|
navBarStore.setRightText("保存", "var(--td-brand-color)", saveRoleList);
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
await loadData();
|
await loadData();
|
||||||
} catch {
|
} catch {
|
||||||
Toast.error("用户角色加载失败");
|
Toast.error("用户角色加载失败");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
onUnmounted(() => navBarStore.clearRight());
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
@@ -307,12 +308,6 @@ onMounted(async () => {
|
|||||||
background: #fff;
|
background: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.save {
|
|
||||||
left: 1rem;
|
|
||||||
right: 1rem;
|
|
||||||
bottom: calc(.75rem + env(safe-area-inset-bottom, 0));
|
|
||||||
position: fixed;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
:global(html.theme-dark) {
|
:global(html.theme-dark) {
|
||||||
|
|||||||
@@ -130,7 +130,8 @@ async function generateInvite(): Promise<void> {
|
|||||||
code: result.code,
|
code: result.code,
|
||||||
expireAt: String(result.expireAt),
|
expireAt: String(result.expireAt),
|
||||||
storeName: isGlobalManager.value ? selectedStoreName.value : currentStoreStore.currentStoreName,
|
storeName: isGlobalManager.value ? selectedStoreName.value : currentStoreStore.currentStoreName,
|
||||||
roleName: selectedRoleName.value
|
roleName: selectedRoleName.value,
|
||||||
|
inviterName: getCurrentUserName()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} finally {
|
} finally {
|
||||||
@@ -138,6 +139,11 @@ async function generateInvite(): Promise<void> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getCurrentUserName(): string {
|
||||||
|
const user = userStore.loginUser.user;
|
||||||
|
return user?.nick || user?.name || "未命名用户";
|
||||||
|
}
|
||||||
|
|
||||||
watch(() => props.visible, async visible => {
|
watch(() => props.visible, async visible => {
|
||||||
if (!visible) {
|
if (!visible) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
+3
-2
@@ -28,6 +28,7 @@ export interface InvitePosterOptions {
|
|||||||
code: string;
|
code: string;
|
||||||
storeName: string;
|
storeName: string;
|
||||||
roleName: string;
|
roleName: string;
|
||||||
|
inviterName: string;
|
||||||
expireAt: number;
|
expireAt: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,7 +217,7 @@ function renderInvitePoster(options: InvitePosterOptions): HTMLCanvasElement {
|
|||||||
context.textAlign = "left";
|
context.textAlign = "left";
|
||||||
context.textBaseline = "middle";
|
context.textBaseline = "middle";
|
||||||
context.font = "700 80px Microsoft YaHei, sans-serif";
|
context.font = "700 80px Microsoft YaHei, sans-serif";
|
||||||
context.fillText("邀请您加入", 64, 120);
|
context.fillText(`${options.inviterName} 邀请您加入`, 64, 120);
|
||||||
context.font = "700 110px Microsoft YaHei, sans-serif";
|
context.font = "700 110px Microsoft YaHei, sans-serif";
|
||||||
context.fillText(options.storeName, 64, 280);
|
context.fillText(options.storeName, 64, 280);
|
||||||
context.font = "700 64px Microsoft YaHei, sans-serif";
|
context.font = "700 64px Microsoft YaHei, sans-serif";
|
||||||
@@ -246,7 +247,7 @@ function renderInvitePoster(options: InvitePosterOptions): HTMLCanvasElement {
|
|||||||
context.fillText("糕店客户管理系统", 600, 1550);
|
context.fillText("糕店客户管理系统", 600, 1550);
|
||||||
context.fillStyle = "#64748B";
|
context.fillStyle = "#64748B";
|
||||||
context.font = "400 40px Microsoft YaHei, sans-serif";
|
context.font = "400 40px Microsoft YaHei, sans-serif";
|
||||||
context.fillText("客户档案 | 事件登记 | 积分激励 | 门店协同", 600, 1645);
|
context.fillText("客户档案 | 事件登记 | 积分激励 | 门店协同 | AI 分析", 600, 1645);
|
||||||
context.fillStyle = "#94A3B8";
|
context.fillStyle = "#94A3B8";
|
||||||
context.font = "400 40px Microsoft YaHei, sans-serif";
|
context.font = "400 40px Microsoft YaHei, sans-serif";
|
||||||
context.fillText("本邀请仅限本人使用,请勿转发", 600, 1760);
|
context.fillText("本邀请仅限本人使用,请勿转发", 600, 1760);
|
||||||
|
|||||||
+37
-5
@@ -34,14 +34,46 @@ export function getRoleDisplayName(role: ManagedUserRole | undefined, roleList:
|
|||||||
return typeof role === "string" ? role : role.name || role.code || "未配置角色";
|
return typeof role === "string" ? role : role.name || role.code || "未配置角色";
|
||||||
}
|
}
|
||||||
|
|
||||||
export function buildEffectiveRoleCodeSet(user: ManagedUser): Set<string> {
|
export function buildEffectiveRoleCodeSet(user: ManagedUser, roleList: Role[] = []): Set<string> {
|
||||||
const roleCodeSet = new Set<string>();
|
const roleCodeSet = new Set<string>();
|
||||||
for (const role of getManagedUserRoleList(user)) {
|
const visitedRoleIds = new Set<string>();
|
||||||
if (typeof role !== "string") {
|
|
||||||
roleCodeSet.add(buildRoleCode(role as Role));
|
function addRole(role: ManagedUserRole | Role): void {
|
||||||
continue;
|
const roleId = typeof role === "string"
|
||||||
|
? roleList.find(item => buildRoleCode(item) === role || item.code === role)?.id
|
||||||
|
: role.id || roleList.find(item => buildRoleCode(item) === buildRoleCode(role as Role))?.id;
|
||||||
|
if (roleId && visitedRoleIds.has(roleId)) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
if (roleId) {
|
||||||
|
visitedRoleIds.add(roleId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof role === "string") {
|
||||||
roleCodeSet.add(role);
|
roleCodeSet.add(role);
|
||||||
|
const separatorIndex = role.indexOf(":");
|
||||||
|
if (-1 < separatorIndex) {
|
||||||
|
roleCodeSet.add(role.slice(separatorIndex + 1));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
roleCodeSet.add(role.code);
|
||||||
|
roleCodeSet.add(buildRoleCode(role as Role));
|
||||||
|
}
|
||||||
|
|
||||||
|
const fullRole = roleId ? roleList.find(item => item.id === roleId) : undefined;
|
||||||
|
for (const childRoleId of fullRole?.childRoleIdList || []) {
|
||||||
|
const childRole = roleList.find(item => item.id === childRoleId);
|
||||||
|
if (childRole) {
|
||||||
|
addRole(childRole);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const role of getManagedUserRoleList(user)) {
|
||||||
|
addRole(role);
|
||||||
|
}
|
||||||
|
for (const roleCode of user.user?.roleList || []) {
|
||||||
|
addRole(roleCode);
|
||||||
}
|
}
|
||||||
return roleCodeSet;
|
return roleCodeSet;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user