feat: R1 重构对称迁移 + 升级依赖 + 配置文件分离

- 命名重构:tenant → customer(对齐后端 R1 重构)
  - Tenant → Customer / tenant_id → customerId
  - tenantStore → customerStore / getTenant/setTenant → getCustomer/setCustomer
  - cookie key tenant → customer, HTTP header tenantId → customerId
- 后端契约更新:AuthResponse 加 sub 字段
- 接口 URL 修复:/auth/oidc/callback → /api/v1/auth/oidc/callback
- 依赖升级:vue 3.5 / element-plus 2.8 / vite 5 / typescript 5.6 / sass 1.79
- 删 node-sass / scss / sass-loader / moment / mock/index.ts
- 配置文件拆分:.env.development / .env.production / .env.example
- 删除冗余 view/auth/auth/callback.vue 副本
- .gitignore 增加 dist / .opencode / tmp
- 新增 AGENT.md 与后端风格对齐
This commit is contained in:
simple321vip
2026-06-22 08:02:21 +08:00
parent bef1906747
commit 4da6832b44
112 changed files with 6616 additions and 4802 deletions
+7 -8
View File
@@ -1,11 +1,11 @@
<template>
<span class="headerAvatar">
<template v-if="picType === 'avatar'">
<el-avatar v-if="useTenantStore.tenant.headerImg" :size="30" :src="avatar" />
<el-avatar v-if="useCustomerStore.customer.headerImg" :size="30" :src="avatar" />
<el-avatar v-else :size="30" :src="noAvatar" />
</template>
<template v-if="picType === 'img'">
<img v-if="useTenantStore.tenant.headerImg" :src="avatar" class="avatar">
<img v-if="useCustomerStore.customer.headerImg" :src="avatar" class="avatar">
<img v-else :src="noAvatar" class="avatar">
</template>
<template v-if="picType === 'file'">
@@ -16,7 +16,7 @@
<script setup lang="ts">
import { computed, ref } from 'vue'
import { tenantStore } from '@/store/modules/tenant'
import { customerStore } from '@/store/modules/customer'
import noAvatarPng from '@/assets/nobody.jpg'
const props = defineProps({
@@ -33,13 +33,13 @@ const props = defineProps({
})
const path = ref(import.meta.env.VITE_BASE_API + '/')
const noAvatar = ref(noAvatarPng)
const useTenantStore = tenantStore()
const useCustomerStore = customerStore()
const avatar = computed(() => {
if (props.picSrc === '') {
if (useTenantStore.tenant.headerImg !== '' && useTenantStore.tenant.headerImg.slice(0, 4) === 'http') {
return useTenantStore.tenant.headerImg
if (useCustomerStore.customer.headerImg !== '' && useCustomerStore.customer.headerImg.slice(0, 4) === 'http') {
return useCustomerStore.customer.headerImg
}
return path.value + useTenantStore.tenant.headerImg
return path.value + useCustomerStore.customer.headerImg
} else {
if (props.picSrc !== '' && props.picSrc.slice(0, 4) === 'http') {
return props.picSrc
@@ -61,7 +61,6 @@ const file = computed(() => {
align-items: center;
margin-right: 8px;
}
.file {
width: 80px;
height: 80px;
+7 -7
View File
@@ -56,7 +56,7 @@
<span class="header-avatar" style="cursor: pointer">
<CustomPic />
<span v-show="!useSettingsStore.isMobile" style="margin-left: 5px">{{
useTenantStore.tenant.account
useCustomerStore.customer.account
}}</span>
<el-icon>
<arrow-down />
@@ -67,10 +67,10 @@
<el-dropdown-menu class="dropdown-group">
<el-dropdown-item>
<span style="font-weight: 600;">
当前角色{{ useTenantStore.tenant.account }}
当前角色{{ useCustomerStore.customer.account }}
</span>
</el-dropdown-item>
<template v-if="useTenantStore.tenant.account">
<template v-if="useCustomerStore.customer.account">
<!-- <el-dropdown-item v-for="item in userStore.userInfo.authorities.filter(i=>i.authorityId!==userStore.userInfo.authorityId)" :key="item.authorityId" @click="changeUserAuth(item.authorityId)">
<span>
切换为{{ item.authorityName }}
@@ -78,7 +78,7 @@
</el-dropdown-item> -->
</template>
<el-dropdown-item icon="avatar" @click="toPerson">个人信息</el-dropdown-item>
<el-dropdown-item icon="reading-lamp" @click="useTenantStore.logout"> </el-dropdown-item>
<el-dropdown-item icon="reading-lamp" @click="useCustomerStore.logout"> </el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
@@ -89,13 +89,13 @@
<script setup lang='ts'>
import CustomPic from "@/components/customPic/index.vue";
import { tenantStore } from '@/store/modules/tenant'
import { customerStore } from '@/store/modules/customer'
import { settingsStore } from '@/store/modules/settings'
import { Message } from "@element-plus/icons-vue"
import { reactive, ref } from "vue";
// -- IMPORT --
const useTenantStore = tenantStore()
const useCustomerStore = customerStore()
const useSettingsStore = settingsStore()
// -- REACTIVE OBJECT --
@@ -131,7 +131,7 @@ const toPerson = () => {
}
useTenantStore.reflush()
useCustomerStore.reflush()
</script>
+17 -57
View File
@@ -4,17 +4,13 @@
</div>
<el-card class="box-card">
<el-form ref="ruleFormRef" :model="loginForm" :rules="loginRules" status-icon label-width="120px"
class="demo-ruleForm">
<el-form>
<div class="title-container">
<h3>秘密基地</h3>
</div>
<div>
<el-avatar :size="28" :src="baiduCloudImage" @click="scan(qrcode)" />
<el-button type="primary" size="large" @click="handleOidcLogin">统一登录</el-button>
</div>
<el-form-item>
其他登录方式暂时还没有哦
</el-form-item>
</el-form>
------------------------------------------------------------
<div>
@@ -31,61 +27,25 @@
</template>
<script lang="ts" setup>
import { reactive, ref } from 'vue'
import type { FormInstance } from 'element-plus'
import { tenantStore } from '../../store/modules/tenant'
import router from '../../router'
import baiduCloudImage from "../../assets/baiducloud.png"
import { config, scan } from '../../const/config'
import { reactive } from 'vue'
import { ElMessage } from 'element-plus'
const handleOidcLogin = () => {
const issuer = import.meta.env.VITE_OIDC_ISSUER
const clientId = import.meta.env.VITE_OIDC_CLIENT_ID
const redirectUri = encodeURIComponent(import.meta.env.VITE_OIDC_REDIRECT_URI)
const scope = encodeURIComponent('openid profile email')
const state = Math.random().toString(36).substring(2)
let qrcode = config.BAIDU_CLOUD_URL + config.RESPONSE_TYPE + config.CLIENT_ID + config.REDIRECT_URI + config.SCOPE + config.DEVICE_ID + config.QR_CODE + config.DISPLAY
const useTenantStore = tenantStore()
const ruleFormRef = ref<FormInstance>()
const loginForm = reactive({
user_id: '',
password: ''
})
const validateUserName = (rule: any, value: string, callback: Function) => {
if (!value) {
callback(new Error("请输入的用户名"))
} else {
callback()
}
}
const validatePassword = (rule: any, value: string, callback: Function) => {
if (!value) {
callback(new Error("请输入密码"))
} else {
callback()
}
}
const loginRules = reactive({
user_id: [{ validator: validateUserName, trigger: 'blur' }],
password: [{ validator: validatePassword, trigger: 'blur' }]
})
const dologin = (form: any) => {
if (!form)
if (!issuer || !clientId) {
ElMessage.error('OIDC 未配置,请联系管理员')
return
// form.validate((valid: any) => {
// if (valid) {
// useTenantStore.login(loginForm.user_id, loginForm.password).then(res => {
// console.log(1)
// router.push({
// path: '/home'
// })
// })
}
// } else {
// return false
// }
// })
sessionStorage.setItem('oidc_state', state)
window.location.href =
`${issuer}/application/o/authorize/?` +
`client_id=${clientId}&redirect_uri=${redirectUri}&response_type=code&scope=${scope}&state=${state}`
}
const openSiteQuery = () => {
+9 -9
View File
@@ -11,8 +11,8 @@
<el-input v-model="register_form.code" />
</el-form-item>
<el-form-item label="tenantId">
<el-input v-model="register_form.tenant_id" :disabled="true" />
<el-form-item label="customerId">
<el-input v-model="register_form.customerId" :disabled="true" />
</el-form-item>
<el-form-item label="account">
@@ -35,17 +35,17 @@ import { reactive } from 'vue'
import { useRoute } from 'vue-router';
import { register_user } from "./../../api/user";
import router from '../../router/index'
import { setTenant, setToken } from '../../utils/auth';
import { setCustomer, setToken } from '../../utils/auth';
const route = useRoute()
const params = route.query
// use phone number to register user(tenant)
// use phone number to register user(customer)
const register_form = reactive({
phone_number: '',
code: '',
tenant_id: params.tenantId as string,
customerId: params.customerId as string,
account: params.account as string,
token: params.token as string
})
@@ -54,13 +54,13 @@ const onSubmit = () => {
register_user(register_form).then((response) => {
if (response.status == 200) {
const tenant = {
id: params.tenantId,
const customer = {
id: params.customerId,
account: params.account
}
setToken(params.token as string)
setTenant(tenant)
setCustomer(customer)
const { href } = router.resolve({
path: '/'
@@ -74,4 +74,4 @@ const onSubmit = () => {
</script>
<style scoped>
</style>
</style>