补足用户切换功能

This commit is contained in:
2026-07-09 16:07:56 +08:00
parent 6f20fec8de
commit fc969390ae
5 changed files with 145 additions and 1 deletions
+30
View File
@@ -0,0 +1,30 @@
import request from '@/utils/request'
import {
DEFAULT_MOCK_USER,
MOCK_USER_HEADER,
MOCK_USER_STORAGE_KEY,
getStoredMockUser,
setStoredMockUser,
} from '@/utils/mockUserStorage'
function getResult(res) {
return res?.result
}
function isSuccessResponse(res) {
return String(res?.code || '') === '0000'
}
export function listMockUsers() {
return request({
url: '/mock/security/users',
method: 'get',
}).then((res) => (isSuccessResponse(res) ? getResult(res) || [] : []))
}
export function getCurrentMockUser() {
return request({
url: '/mock/security/current',
method: 'get',
}).then((res) => (isSuccessResponse(res) ? getResult(res) || null : null))
}
+93 -1
View File
@@ -35,6 +35,21 @@
<div class="sider-footer"> <div class="sider-footer">
<a-button block @click="router.push('/')">返回首页</a-button> <a-button block @click="router.push('/')">返回首页</a-button>
<div class="mock-user-panel">
<div class="mock-user-label">测试用户切换</div>
<a-select
v-model:value="selectedMockUserKey"
class="mock-user-select"
:options="mockUserOptions"
:loading="mockUserLoading"
placeholder="请选择测试用户"
@change="handleMockUserChange"
/>
<div v-if="currentMockUser" class="mock-user-meta">
{{ currentMockUser.systemType === 'manage' ? '管理端' : currentMockUser.systemType === 'business' ? '业务端' : '平台' }}
· {{ currentMockUser.orgName }}
</div>
</div>
</div> </div>
</a-layout-sider> </a-layout-sider>
@@ -53,8 +68,14 @@
</template> </template>
<script setup> <script setup>
import { computed } from 'vue' import { computed, onMounted, ref } from 'vue'
import { useRoute, useRouter } from 'vue-router' import { useRoute, useRouter } from 'vue-router'
import { message } from 'ant-design-vue'
import {
getCurrentMockUser,
listMockUsers,
} from '@/api/mockUser'
import { getStoredMockUser, setStoredMockUser } from '@/utils/mockUserStorage'
import { import {
FileDoneOutlined, FileDoneOutlined,
FileTextOutlined, FileTextOutlined,
@@ -65,6 +86,10 @@ import {
const route = useRoute() const route = useRoute()
const router = useRouter() const router = useRouter()
const mockUserLoading = ref(false)
const mockUserList = ref([])
const currentMockUser = ref(null)
const selectedMockUserKey = ref(getStoredMockUser())
const selectedKey = computed(() => { const selectedKey = computed(() => {
if (route.path.startsWith('/contract-console/sign')) { if (route.path.startsWith('/contract-console/sign')) {
@@ -88,9 +113,49 @@ const selectedKey = computed(() => {
const currentTitle = computed(() => route.meta?.title || '合同管理') const currentTitle = computed(() => route.meta?.title || '合同管理')
const mockUserOptions = computed(() =>
mockUserList.value.map((item) => ({
label: `${item.displayName} (${item.orgId})`,
value: item.key,
})),
)
function handleMenuClick({ key }) { function handleMenuClick({ key }) {
router.push(key) router.push(key)
} }
async function loadMockUsers() {
mockUserLoading.value = true
try {
mockUserList.value = await listMockUsers()
const availableKeys = new Set(mockUserList.value.map((item) => item.key))
if (!availableKeys.has(selectedMockUserKey.value) && mockUserList.value.length > 0) {
selectedMockUserKey.value = mockUserList.value[0].key
setStoredMockUser(selectedMockUserKey.value)
}
} finally {
mockUserLoading.value = false
}
}
async function loadCurrentMockUser() {
currentMockUser.value = await getCurrentMockUser()
if (currentMockUser.value?.key) {
selectedMockUserKey.value = currentMockUser.value.key
setStoredMockUser(currentMockUser.value.key)
}
}
function handleMockUserChange(value) {
setStoredMockUser(value)
message.success('测试用户已切换,正在刷新页面数据')
window.location.reload()
}
onMounted(async () => {
await loadMockUsers()
await loadCurrentMockUser()
})
</script> </script>
<style scoped> <style scoped>
@@ -149,6 +214,33 @@ function handleMenuClick({ key }) {
padding: 16px 20px 20px; padding: 16px 20px 20px;
} }
.mock-user-panel {
margin-bottom: 12px;
padding: 12px;
border-radius: 14px;
background: rgba(255, 255, 255, 0.78);
border: 1px solid rgba(37, 99, 235, 0.12);
box-shadow: 0 10px 24px rgba(15, 23, 42, 0.04);
}
.mock-user-label {
font-size: 12px;
font-weight: 700;
color: #334155;
margin-bottom: 8px;
}
.mock-user-select {
width: 100%;
}
.mock-user-meta {
margin-top: 8px;
font-size: 12px;
line-height: 1.5;
color: #64748b;
}
.contract-header { .contract-header {
height: auto; height: auto;
background: rgba(255, 255, 255, 0.96); background: rgba(255, 255, 255, 0.96);
+15
View File
@@ -0,0 +1,15 @@
export const MOCK_USER_STORAGE_KEY = 'stamp_mock_user'
export const DEFAULT_MOCK_USER = 'admin'
export const MOCK_USER_HEADER = 'X-Mock-User'
export function getStoredMockUser() {
return localStorage.getItem(MOCK_USER_STORAGE_KEY) || DEFAULT_MOCK_USER
}
export function setStoredMockUser(userKey) {
if (!userKey) {
localStorage.removeItem(MOCK_USER_STORAGE_KEY)
return
}
localStorage.setItem(MOCK_USER_STORAGE_KEY, userKey)
}
+3
View File
@@ -1,4 +1,5 @@
import axios from 'axios' import axios from 'axios'
import { DEFAULT_MOCK_USER, getStoredMockUser, MOCK_USER_HEADER } from '@/utils/mockUserStorage'
import { message, Modal, notification } from 'ant-design-vue' import { message, Modal, notification } from 'ant-design-vue'
const service = axios.create({ const service = axios.create({
@@ -12,6 +13,8 @@ service.interceptors.request.use(
if (token) { if (token) {
config.headers['Authorization'] = 'Bearer ' + token config.headers['Authorization'] = 'Bearer ' + token
} }
const mockUser = getStoredMockUser() || DEFAULT_MOCK_USER
config.headers[MOCK_USER_HEADER] = mockUser
return config return config
}, },
(error) => Promise.reject(error), (error) => Promise.reject(error),
+4
View File
@@ -35,6 +35,10 @@ export default defineConfig({
target: 'http://127.0.0.1:8899', target: 'http://127.0.0.1:8899',
changeOrigin: true, changeOrigin: true,
}, },
'/mock': {
target: 'http://127.0.0.1:8899',
changeOrigin: true,
},
'/trans': { '/trans': {
target: 'http://127.0.0.1:8899', target: 'http://127.0.0.1:8899',
changeOrigin: true, changeOrigin: true,