diff --git a/server/internal/consts/im_user.go b/server/internal/consts/im_user.go index 75206aa..b9f1064 100644 --- a/server/internal/consts/im_user.go +++ b/server/internal/consts/im_user.go @@ -12,6 +12,7 @@ import ( func init() { dict.RegisterEnums("ImUserStateOptions", "IM用户状态选项", ImUserStateOptions) + dict.RegisterEnums("ImUserListStateOptions", "IM用户列表状态选项", ImUserListStateOptions) dict.RegisterEnums("ImUserRegisterTypeOptions", "IM用户注册方式选项", ImUserRegisterTypeOptions) } @@ -35,8 +36,14 @@ const ( ) var ImUserStateOptions = []*model.Option{ - dict.GenSuccessOption(ImUserStateOk, "正常"), - dict.GenErrorOption(ImUserStateSuspended, "已停用"), - dict.GenDefaultOption(ImUserStateDeleted, "已删除"), + dict.GenSuccessOption(ImUserStateOk, "启用"), + dict.GenErrorOption(ImUserStateSuspended, "封禁"), + dict.GenDefaultOption(ImUserStateDeleted, "已注销"), dict.GenWarningOption(ImUserStateUndefined, "未定义"), } + +var ImUserListStateOptions = []*model.Option{ + dict.GenSuccessOption(ImUserStateOk, "启用"), + dict.GenErrorOption(ImUserStateSuspended, "封禁"), + dict.GenDefaultOption(ImUserStateDeleted, "已注销"), +} diff --git a/server/storage/data/generate/im_user_policy_group_seed.sql b/server/storage/data/generate/im_user_policy_group_seed.sql new file mode 100644 index 0000000..4d933f1 --- /dev/null +++ b/server/storage/data/generate/im_user_policy_group_seed.sql @@ -0,0 +1,46 @@ +-- Initialize assignable policy groups for every active IM tenant. +-- Safe to rerun: tenant_id + group_code is unique. +SET NAMES utf8mb4; +USE `hotgo`; + +INSERT INTO `im_user_policy_groups` + (`tenant_id`, `group_code`, `group_name`, `priority`, `status`, `policy_json`, `ip_whitelist`, `ip_blacklist`, `version`, `remark`, `created_by`, `updated_by`) +SELECT + `id`, 'default_standard', '默认用户组', 100, 1, + JSON_OBJECT( + 'allow_add_friend', TRUE, 'allow_join_group', TRUE, 'max_friend_count', 5000, + 'allow_upload_file', TRUE, 'direct_add_friend', FALSE, 'allow_create_group', TRUE, + 'allow_group_message', TRUE, 'allow_private_message', TRUE, + 'allow_qrcode_add_friend', TRUE, 'allow_group_member_profile', TRUE, + 'hide_profile_when_friend_disabled', TRUE + ), JSON_ARRAY(), JSON_ARRAY(), 1, '系统初始化:默认用户权限', 0, 0 +FROM `im_tenant` WHERE `state` = 1 +ON DUPLICATE KEY UPDATE `group_name` = VALUES(`group_name`), `status` = 1, `updated_at` = CURRENT_TIMESTAMP(3); + +INSERT INTO `im_user_policy_groups` + (`tenant_id`, `group_code`, `group_name`, `priority`, `status`, `policy_json`, `ip_whitelist`, `ip_blacklist`, `version`, `remark`, `created_by`, `updated_by`) +SELECT + `id`, 'default_trusted', '可信用户组', 90, 1, + JSON_OBJECT( + 'allow_add_friend', TRUE, 'allow_join_group', TRUE, 'max_friend_count', 10000, + 'allow_upload_file', TRUE, 'direct_add_friend', TRUE, 'allow_create_group', TRUE, + 'allow_group_message', TRUE, 'allow_private_message', TRUE, + 'allow_qrcode_add_friend', TRUE, 'allow_group_member_profile', TRUE, + 'hide_profile_when_friend_disabled', TRUE + ), JSON_ARRAY(), JSON_ARRAY(), 1, '系统初始化:可信用户权限', 0, 0 +FROM `im_tenant` WHERE `state` = 1 +ON DUPLICATE KEY UPDATE `group_name` = VALUES(`group_name`), `status` = 1, `updated_at` = CURRENT_TIMESTAMP(3); + +INSERT INTO `im_user_policy_groups` + (`tenant_id`, `group_code`, `group_name`, `priority`, `status`, `policy_json`, `ip_whitelist`, `ip_blacklist`, `version`, `remark`, `created_by`, `updated_by`) +SELECT + `id`, 'default_guest', '访客用户组', 60, 1, + JSON_OBJECT( + 'allow_add_friend', FALSE, 'allow_join_group', TRUE, 'max_friend_count', 0, + 'allow_upload_file', FALSE, 'direct_add_friend', FALSE, 'allow_create_group', FALSE, + 'allow_group_message', TRUE, 'allow_private_message', TRUE, + 'allow_qrcode_add_friend', FALSE, 'allow_group_member_profile', FALSE, + 'hide_profile_when_friend_disabled', TRUE + ), JSON_ARRAY(), JSON_ARRAY(), 1, '系统初始化:访客用户权限', 0, 0 +FROM `im_tenant` WHERE `state` = 1 +ON DUPLICATE KEY UPDATE `group_name` = VALUES(`group_name`), `status` = 1, `updated_at` = CURRENT_TIMESTAMP(3); diff --git a/web/src/views/imUser/index.vue b/web/src/views/imUser/index.vue index ce99325..60bf208 100644 --- a/web/src/views/imUser/index.vue +++ b/web/src/views/imUser/index.vue @@ -330,7 +330,7 @@ type: record.state === 0 ? 'error' : 'default', onClick: handleBanToggle.bind(null, record), auth: [record.state === 0 ? '/imUser/ban' : '/imUser/unban'], - ifShow: record.state !== 20, + ifShow: record.state === 0 || record.state === 10, }, { label: '强制下线', @@ -429,8 +429,9 @@ } } - function openAdjustGroup(record: State) { + async function openAdjustGroup(record: State) { operationUser.value = record; + await loadPolicyGroupOptions(record.tenantId); adjustGroupId.value = record.policyGroupId || null; groupVisible.value = true; } @@ -567,15 +568,17 @@ onMounted(async () => { loadOptions(); + let tenantId = currentTenantId(); if (isPlatformAdmin.value) { await loadTenantOptions(); if (tenantOptions.value.length > 0) { - await setFieldsValue({ tenantId: tenantOptions.value[0].value }); + tenantId = Number(tenantOptions.value[0].value); + await setFieldsValue({ tenantId }); } else { message.warning('暂无可用租户'); } } - await loadPolicyGroupOptions(currentTenantId()); + await loadPolicyGroupOptions(tenantId); reloadTable(); }); diff --git a/web/src/views/imUser/model.ts b/web/src/views/imUser/model.ts index 6790cb0..95b0164 100644 --- a/web/src/views/imUser/model.ts +++ b/web/src/views/imUser/model.ts @@ -1,10 +1,11 @@ import { computed, h, ref } from 'vue'; -import { NAvatar, NImage, NTag } from 'naive-ui'; +import { NImage, NTag } from 'naive-ui'; import { cloneDeep } from 'lodash-es'; import { FormSchema } from '@/components/Form'; import { useDictStore } from '@/store/modules/dict'; import { List as TenantList } from '@/api/imTenant'; import { List as PolicyGroupList } from '@/api/imUserPolicyGroup'; +import defaultAvatar from '@/assets/images/schoolboy.png'; const dict = useDictStore(); @@ -110,7 +111,7 @@ export const schemas = ref([ label: '状态', componentProps: { clearable: true, - options: dict.getOption('ImUserStateOptions'), + options: dict.getOption('ImUserListStateOptions'), placeholder: '全部', }, }, @@ -139,14 +140,14 @@ export const columns = [ align: 'left', width: 80, render(row: State) { - if (row.avatar) { - return h(NImage, { width: 40, height: 40, src: row.avatar, objectFit: 'cover' }); - } - return h( - NAvatar, - { size: 40 }, - { default: () => (row.nickname || row.username || '?').slice(0, 1) } - ); + return h(NImage, { + width: 40, + height: 40, + src: row.avatar || defaultAvatar, + fallbackSrc: defaultAvatar, + objectFit: 'cover', + previewDisabled: !row.avatar, + }); }, }, { @@ -243,7 +244,7 @@ export const deviceColumns = [ // 加载字典数据选项 export function loadOptions() { - dict.loadOptions(['ImUserStateOptions', 'ImUserRegisterTypeOptions']); + dict.loadOptions(['ImUserStateOptions', 'ImUserListStateOptions', 'ImUserRegisterTypeOptions']); } export async function loadTenantOptions() { @@ -256,7 +257,7 @@ export async function loadTenantOptions() { } export async function loadPolicyGroupOptions(tenantId: number) { - const res = await PolicyGroupList({ tenantId, page: 1, pageSize: 200 }); + const res = await PolicyGroupList({ tenantId, status: 1, page: 1, perPage: 200 }); policyGroupOptions.value = (res?.list || []).map((item) => ({ label: item.groupName, value: item.id,