feat(ui): remove in-app entity switcher, entity fixed at login

- MainLayout/ReportCenter: drop switch-entity switcher, keep read-only entity tag
- KPIList/PredictDashboard/GrowthQuality: entity selectors locked to session entity
- api/index.ts: drop switchEntity/myEntities wrappers (endpoint kept for compat)
- sidebar brand now shows logged-in entity name

(cma-remove-inapp-entity-switcher-20260914)
This commit is contained in:
Hermes CI Fix
2026-09-14 10:15:23 +08:00
parent 53c642b644
commit 1b73dbb272
6 changed files with 38 additions and 186 deletions
+5 -34
View File
@@ -35,18 +35,10 @@
<!-- 右侧:搜索+表格 -->
<div class="right-content">
<!-- 企业选择器 -->
<!-- 企业只读标识(不可点):账套由登录窗口选定,页内无切换入口 -->
<div class="entity-selector">
<span class="entity-label">🌐 企业:</span>
<el-select v-model="currentEntityId" @change="onEntityChange" style="width:200px">
<el-option
v-for="e in entities"
:key="e.id"
:label="e.short_name + ' / ' + e.name"
:value="e.id"
/>
</el-select>
<span class="entity-name-hint">{{ currentEntityName }}</span>
<span class="entity-label">企业:</span>
<el-tag size="small" type="primary" effect="plain">{{ currentEntityName }}</el-tag>
</div>
<!-- 搜索栏 -->
@@ -413,7 +405,7 @@
<script setup lang="ts">
import { ref, reactive, onMounted, computed } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { kpiApi, templateApi, dashboardApi, entityApi, userApi, orgApi } from '../api/index'
import { kpiApi, templateApi, dashboardApi, userApi, orgApi } from '../api/index'
import MyDialog from '../components/MyDialog.vue'
import { useFormGuard, trackDialogForm } from '../composables/useFormGuard'
@@ -431,7 +423,6 @@ const searchCategory = ref('')
const searchStatus = ref('active')
// ── 企业选择 ──
const entities = ref<any[]>([])
const currentEntityId = ref(Number(localStorage.getItem('cma_entity_id') || 1))
const currentEntityName = ref(localStorage.getItem('cma_entity_name') || '酣客')
@@ -880,29 +871,9 @@ async function doInstantiate() {
}
}
// ── 企业选择 ──
async function loadEntities() {
try {
const r: any = await entityApi.list()
entities.value = r.data || []
// Find current entity name
const cur = entities.value.find((e: any) => e.id === currentEntityId.value)
if (cur) currentEntityName.value = cur.short_name || cur.name
} catch (e) {
console.error('加载企业列表失败', e)
}
}
function onEntityChange(val: number) {
const cur = entities.value.find((e: any) => e.id === val)
currentEntityName.value = cur ? (cur.short_name || cur.name) : ''
page.value = 1
loadKpis()
loadCategories()
}
// ── 企业选择:已收敛为只读(2026-09-14 取消应用内切换,账套由登录窗口选定)──
onMounted(() => {
loadEntities()
loadCategories()
loadKpis()
loadDepts()
+5 -8
View File
@@ -331,10 +331,8 @@
<template #header>预测参数</template>
<el-form label-position="top">
<el-form-item label="企业实体">
<el-select v-model="cfEntityId" style="width:100%;">
<el-option label="陕西酣客(白酒经销)" :value="1" />
<el-option label="陕西博海科技(IT服务)" :value="2" />
</el-select>
<!-- 只读:账套由登录窗口选定,页内不可切换 -->
<el-tag size="small" type="primary" effect="plain">{{ cfEntityName }}</el-tag>
</el-form-item>
<el-form-item label="当前现金余额(万元)">
<el-input-number v-model="cfCurrentCash" :min="0" :precision="1" style="width:100%;" />
@@ -610,10 +608,9 @@ async function doScenario() {
const cfLoading = ref(false)
const cfEntityId = ref(Number(localStorage.getItem('cma_entity_id') || 1))
// 监听企业切换
window.addEventListener('storage', (e) => {
if (e.key === 'cma_entity_id') cfEntityId.value = Number(e.newValue || 1)
})
// 账套由登录窗口确定(应用内无切换入口):不再监听 cma_entity_id 变更,
// 本页预测请求沿用会话账套(后端 token 优先,entity_id 以 token 绑定为准)。
const cfEntityName = ref(localStorage.getItem('cma_entity_name') || `企业 #${Number(localStorage.getItem('cma_entity_id') || 1)}`)
const cfCurrentCash = ref(30)
const cfDays = ref(30)
const cfResult = ref<any>({})
+6 -56
View File
@@ -4,18 +4,8 @@
<div class="report-header">
<h3 class="page-title">📊 CMA管理报表</h3>
<div class="header-right">
<!-- 固定企业版(Phase C):页内切换下拉隐藏,显示当前企业 tag -->
<el-tag v-if="isFixedEntity()" size="small" type="primary" effect="plain">{{ currentEntityNameTag }}</el-tag>
<el-select
v-else
v-model="currentEntityId"
size="small"
style="width:180px"
placeholder="选择企业"
@change="onEntityChange"
>
<el-option v-for="e in entities" :key="e.id" :label="e.short_name + ' / ' + e.name" :value="e.id" />
</el-select>
<!-- 企业只读标识(不可点):账套由登录窗口选定,页内无切换入口 -->
<el-tag size="small" type="primary" effect="plain" class="entity-tag">{{ currentEntityNameTag }}</el-tag>
<el-date-picker
v-model="reportPeriod"
type="month"
@@ -630,18 +620,17 @@
import { ref, reactive, computed, onMounted, nextTick } from 'vue'
import { ElMessage } from 'element-plus'
import axios from 'axios'
import { isFixedEntity, getFixedEntityId } from '../utils/entity'
import { getFixedEntityId } from '../utils/entity'
// ── 状态 ──
const loading = ref(false)
const activeTab = ref('profit')
const reportPeriod = ref('2026-06')
// ── 企业选择(新30号准则报表联动)──
const entities = ref<any[]>([])
// ── 当前企业(只读):2026-09-14 需求——登录即定企业,页内无切换入口
const currentEntityId = ref(Number(localStorage.getItem('cma_entity_id') || 1))
// 固定企业版:页内切换下拉隐藏,右上角显示当前企业 tag
// 右上角只读企业标识(不可点)
const currentEntityNameTag = computed(() => {
const f = getFixedEntityId()
const n = localStorage.getItem('cma_entity_name')
@@ -649,50 +638,12 @@ const currentEntityNameTag = computed(() => {
})
function getEntityId() {
// 固定企业版恒取构建锁定值(防 localStorage 残留串账套);切换版取登录/切换写入值
// 固定企业版恒取构建锁定值(防 localStorage 残留串账套);默认版取登录时写入值
const f = getFixedEntityId()
if (f !== undefined) return f
return Number(localStorage.getItem('cma_entity_id') || currentEntityId.value || 1)
}
async function loadEntities() {
try {
const r: any = await api.get('/auth/my-entities')
entities.value = r.data || r || []
const e = entities.value.find((x: any) => x.id === currentEntityId.value)
if (e) localStorage.setItem('cma_entity_name', e.short_name || e.name || '')
} catch {
entities.value = []
}
}
async function onEntityChange(id: number) {
// 账套模式:切换走 switch-entity 重新签发token + 整页刷新
if (id === Number(localStorage.getItem('cma_entity_id'))) return
try {
const r: any = await api.post('/auth/switch-entity', { entity_id: id })
localStorage.setItem('cma_token', r.token)
localStorage.setItem('cma_entity_id', String(r.entity_id))
localStorage.setItem('cma_entity_name', r.entity_short_name || r.entity_name || '')
ElMessage.success(`已切换企业:${r.entity_short_name || r.entity_name || id}`)
location.reload()
} catch (e: any) {
ElMessage.error(e?.response?.data?.detail || '切换失败')
}
}
// 跨页面同步:其他页面切换企业时联动刷新(固定企业版忽略——该版本不存在切换)
if (typeof window !== 'undefined') {
window.addEventListener('storage', (ev: StorageEvent) => {
if (isFixedEntity()) return
if (ev.key === 'cma_entity_id' && ev.newValue) {
currentEntityId.value = Number(ev.newValue)
loadAll()
loadStatutory()
}
})
}
// API 配置
const api = axios.create({ baseURL: '/api/cma', timeout: 30000 })
api.interceptors.request.use((config: any) => {
@@ -1078,7 +1029,6 @@ function onBudgetSort(sort: any) {
}
onMounted(() => {
if (!isFixedEntity()) loadEntities()
loadKpiOptions()
loadAll()
loadStatutory()