1.将部门修改为渠道,并且所有dice_表关联渠道表

2.将所有配置表,记录表设置关联渠道
3.优化后台页面设置
This commit is contained in:
2026-05-19 09:49:02 +08:00
parent 085454fb78
commit dd264b1e97
143 changed files with 4741 additions and 1254 deletions

View File

@@ -0,0 +1,6 @@
/** @deprecated 请使用 useChannelDeptScope */
export {
DEFAULT_CHANNEL_ID,
useChannelDeptScope as useChannelConfigScope,
type ChannelTreeNode
} from './useChannelDeptScope'

View File

@@ -0,0 +1,230 @@
import type { InjectionKey, Ref, ComputedRef } from 'vue'
import { useRoute } from 'vue-router'
import deptApi from '@/api/system/dept'
import { useUserStore } from '@/store/modules/user'
import { isConfigChannelRoute, isRoleChannelRoute, isSuperAdminUser } from '@/utils/channelLayout'
export interface ChannelTreeNode {
id: number
label: string
children?: ChannelTreeNode[]
}
/** 默认配置模板dept_id = 0 */
export const DEFAULT_CHANNEL_ID = 0
export interface ChannelDeptScopeContext {
treeData: Ref<ChannelTreeNode[]>
selectedDeptId: Ref<number>
loadingChannels: Ref<boolean>
isSuperAdmin: Ref<boolean>
selectedDeptLabel: Ref<string>
deptQueryParams: ComputedRef<{ dept_id: number }>
isConfigScope: ComputedRef<boolean>
showDefaultTemplate: ComputedRef<boolean>
}
export const CHANNEL_DEPT_SCOPE_KEY: InjectionKey<ChannelDeptScopeContext> =
Symbol('channelDeptScope')
export function provideChannelDeptScope(ctx: ChannelDeptScopeContext) {
provide(CHANNEL_DEPT_SCOPE_KEY, ctx)
}
export function useInjectedChannelDept(): ChannelDeptScopeContext | null {
return inject(CHANNEL_DEPT_SCOPE_KEY, null)
}
/** 超管全局渠道栏:创建并 provide 渠道上下文 */
export function useChannelDeptScope() {
const route = useRoute()
const userStore = useUserStore()
const treeData = ref<ChannelTreeNode[]>([])
const selectedDeptId = ref<number>(DEFAULT_CHANNEL_ID)
const loadingChannels = ref(false)
const isConfigScope = computed(() => isConfigChannelRoute(route))
const isRoleScope = computed(() => isRoleChannelRoute(route))
const showDefaultTemplate = computed(() => isConfigScope.value || isRoleScope.value)
const isSuperAdmin = computed(() => isSuperAdminUser())
const selectedDeptLabel = computed(() => {
const find = (nodes: ChannelTreeNode[]): string => {
for (const n of nodes) {
if (n.id === selectedDeptId.value) {
return n.label
}
if (n.children?.length) {
const sub = find(n.children)
if (sub) return sub
}
}
return ''
}
return find(treeData.value)
})
const deptQueryParams = computed(() => {
const id = selectedDeptId.value
if (!showDefaultTemplate.value && id <= 0) {
return { dept_id: 0 }
}
return { dept_id: id }
})
const loadChannels = async () => {
loadingChannels.value = true
try {
const list = await deptApi.accessDept()
const channels = Array.isArray(list) ? list : []
const nodes: ChannelTreeNode[] = channels.map((item: Record<string, unknown>) => ({
id: Number(item.id ?? item.value),
label: String(item.label ?? item.name ?? item.id)
}))
if (isSuperAdmin.value) {
if (showDefaultTemplate.value) {
treeData.value = [{ id: DEFAULT_CHANNEL_ID, label: '' }, ...nodes]
if (!treeData.value.some((n) => n.id === selectedDeptId.value)) {
selectedDeptId.value = DEFAULT_CHANNEL_ID
}
} else {
treeData.value = nodes
if (nodes.length > 0) {
const valid = nodes.some((n) => n.id === selectedDeptId.value)
if (!valid || selectedDeptId.value <= 0) {
selectedDeptId.value = nodes[0].id
}
}
}
} else {
treeData.value = nodes
if (nodes.length > 0) {
selectedDeptId.value = nodes[0].id
}
}
} finally {
loadingChannels.value = false
}
}
const handleChannelClick = (data: ChannelTreeNode) => {
selectedDeptId.value = Number(data.id)
}
const ctx: ChannelDeptScopeContext = {
treeData,
selectedDeptId,
loadingChannels,
isSuperAdmin,
selectedDeptLabel,
deptQueryParams,
isConfigScope,
showDefaultTemplate
}
onMounted(() => {
loadChannels()
})
return {
...ctx,
loadChannels,
handleChannelClick,
provideScope: () => provideChannelDeptScope(ctx)
}
}
/** 将当前选中渠道写入列表查询参数并刷新 */
export function bindChannelDeptToSearchParams(
searchParams: Record<string, unknown>,
refresh: () => void,
options?: { immediate?: boolean; enabled?: boolean }
) {
const channel = useInjectedChannelDept()
if (!channel || options?.enabled === false) {
return
}
const apply = (deptId: number) => {
if (!channel.showDefaultTemplate.value && deptId <= 0) {
return
}
searchParams.dept_id = deptId
refresh()
}
watch(
() => channel.selectedDeptId.value,
(deptId) => apply(deptId),
{ immediate: options?.immediate ?? true }
)
}
/** 工作台等非 useTable 页面:渠道切换时重新拉数 */
export function useChannelDeptReload(loadFn: () => void | Promise<void>) {
const channel = useInjectedChannelDept()
if (!channel) {
onMounted(() => {
void loadFn()
})
return
}
watch(
() => channel.selectedDeptId.value,
(deptId) => {
if (!channel.showDefaultTemplate.value && deptId <= 0) {
return
}
void loadFn()
},
{ immediate: true }
)
}
/** 请求参数:业务页附带 dept_id渠道管理员固定本渠道 */
export function getChannelDeptRequestParams(): { dept_id?: number } {
const channel = useInjectedChannelDept()
if (channel?.isSuperAdmin.value) {
const deptId = channel.selectedDeptId.value
if (!channel.showDefaultTemplate.value && deptId <= 0) {
return {}
}
if (deptId > 0) {
return { dept_id: deptId }
}
if (channel.showDefaultTemplate.value) {
return { dept_id: deptId }
}
return {}
}
const userStore = useUserStore()
const dept = userStore.info?.department
if (dept && Number(dept.id) > 0) {
return { dept_id: Number(dept.id) }
}
return {}
}
/** 保存/更新时附带 dept_id优先渠道栏选中值其次表单/行数据中的 dept_id */
export function withChannelDeptParams<T extends Record<string, unknown>>(payload: T): T {
const extra = getChannelDeptRequestParams()
if ('dept_id' in extra) {
return { ...payload, ...extra }
}
const rowDeptId = payload.dept_id
if (rowDeptId !== undefined && rowDeptId !== null && rowDeptId !== '') {
const num = Number(rowDeptId)
if (num > 0) {
return { ...payload, dept_id: num }
}
}
const channel = useInjectedChannelDept()
if (channel && channel.selectedDeptId.value > 0) {
return { ...payload, dept_id: channel.selectedDeptId.value }
}
return payload
}