Commit 7d82bc09 by yuzhenWang

添加保险产品

parent ea074136
# 页面标题
VITE_APP_TITLE = 若依管理系统
VITE_APP_TITLE = 银盾中台系统
# 开发环境配置
VITE_APP_ENV = 'development'
......
# 页面标题
VITE_APP_TITLE = 若依管理系统
VITE_APP_TITLE = 银盾中台系统
# 生产环境配置
VITE_APP_ENV = 'production'
......@@ -8,4 +8,4 @@ VITE_APP_ENV = 'production'
VITE_APP_BASE_API = '/prod-api'
# 是否在打包时开启压缩,支持 gzip 和 brotli
VITE_BUILD_COMPRESS = gzip
\ No newline at end of file
VITE_BUILD_COMPRESS = gzip
# 页面标题
VITE_APP_TITLE = 若依管理系统
VITE_APP_TITLE = 银盾中台系统
# 生产环境配置
VITE_APP_ENV = 'staging'
......@@ -8,4 +8,4 @@ VITE_APP_ENV = 'staging'
VITE_APP_BASE_API = '/stage-api'
# 是否在打包时开启压缩,支持 gzip 和 brotli
VITE_BUILD_COMPRESS = gzip
\ No newline at end of file
VITE_BUILD_COMPRESS = gzip
......@@ -6,8 +6,8 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="renderer" content="webkit">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<link rel="icon" href="/favicon.ico">
<title>若依管理系统</title>
<link rel="icon" href="/companyLogo.png">
<title>银盾中台系统</title>
<!--[if lt IE 11]><script>window.location.href='/html/ie.html';</script><![endif]-->
<style>
html,
......@@ -212,4 +212,4 @@
<script type="module" src="/src/main.js"></script>
</body>
</html>
\ No newline at end of file
</html>
import request from '@/utils/request'
// 修改上传图片方法,添加正确的请求配置
export function uploadImage(data) {
console.log('data', data)
return request({
url: '/oss/api/oss/upload',
data: data,
method: 'post',
// 添加以下配置
headers: {
'Content-Type': 'multipart/form-data' // 明确指定为multipart类型
},
// 如果使用axios,需要设置这个参数
transformRequest: [
function (data) {
return data
}
]
})
}
// 查询用户是否有访问项目的权限
export function getVisitPermission(projectBizId) {
return request({
url: '/user/api/sysUser/login/permission/project/visit?projectBizId=' + projectBizId,
method: 'get'
})
}
import request from '@/utils/request'
// 查询保险产品列表
export function getInsuranceProductList(data) {
return request({
url: '/insurance/base/api/insuranceProduct/page',
method: 'post',
data: data
})
}
// 编辑产品状态
export function editProductStatus(productBizId, status) {
return request({
url: `/insurance/base/api/insuranceProduct/edit/status?productBizId=${productBizId}&status=${status}`,
method: 'patch'
})
}
// 添加产品
export function addInsuranceProduct(data) {
return request({
url: '/insurance/base/api/insuranceProduct/add',
method: 'post',
data: data
})
}
// 修改产品
export function editInsuranceProduct(data) {
return request({
url: '/insurance/base/api/insuranceProduct/edit',
method: 'put',
data: data
})
}
// 获取产品详情
export function getProductDetail(productBizId) {
return request({
url: `/insurance/base/api/insuranceProduct/detail?productBizId=${productBizId}`,
method: 'get'
})
}
// 查询保险计划产品列表
export function getInsuranceProducPlanList(data) {
return request({
url: '/insurance/base/api/insuranceProductPlan/page',
method: 'post',
data: data
})
}
// 编辑产品计划状态
export function editPlanStatus(planBizId, status) {
return request({
url: `/insurance/base/api/insuranceProductPlan/edit/status?planBizId=${planBizId}&status=${status}`,
method: 'patch'
})
}
// 添加保险计划产品列表
export function addInsuranceProducPlan(data) {
return request({
url: '/insurance/base/api/insuranceProductPlan/add',
method: 'post',
data: data
})
}
// 添加保险计划产品列表
export function getInsuranceProducPlanDetail(planBizId) {
return request({
url: `/insurance/base/api/insuranceProductPlan/detail?planBizId=${planBizId}`,
method: 'get'
})
}
// 修改产品计划
export function editInsuranceProducPlan(data) {
return request({
url: '/insurance/base/api/insuranceProductPlan/edit',
method: 'put',
data: data
})
}
//查询租户保险产品列表
export function getRelTenantInsuranceList(data) {
return request({
url: '/insurance/base/api/relTenantInsuranceProduct/page',
method: 'post',
data: data
})
}
//查询租户保险产品导入列表
export function getImportRelTenantInsuranceList(data) {
return request({
url: '/insurance/base/api/relTenantInsuranceProduct/select/product/page',
method: 'post',
data: data
})
}
//租户导入保险产品
export function addImportInsuranceProductList(data) {
return request({
url: '/insurance/base/api/relTenantInsuranceProduct/add/product/list',
method: 'post',
data: data
})
}
// 删除租户和保险产品关系
export function delInsuranceProduct(id) {
return request({
url: '/insurance/base/api/relTenantInsuranceProduct/del?id=' + id,
method: 'delete'
})
}
// 查询保险附加产品列表
export function getAdditionalProductList(data) {
return request({
url: '/insurance/base/api/insuranceAdditionalProduct/page',
method: 'post',
data: data
})
}
// 添加保险附加产品
export function addInsuranceAdditionalProduct(data) {
return request({
url: '/insurance/base/api/insuranceAdditionalProduct/add',
method: 'post',
data: data
})
}
// 获取附加产品详情
export function getAdditionalProductDetail(additionalProductBizId) {
return request({
url: `/insurance/base/api/insuranceAdditionalProduct/detail?additionalProductBizId=${additionalProductBizId}`,
method: 'get'
})
}
// 编辑附加产品信息
export function editAdditionalProduct(data) {
return request({
url: '/insurance/base/api/insuranceAdditionalProduct/edit',
method: 'put',
data: data
})
}
// 编辑附加产品状态
export function editAdditionalProductStatus(additionalProductBizId, status) {
return request({
url: `/insurance/base/api/insuranceAdditionalProduct/edit/status?additionalProductBizId=${additionalProductBizId}&status=${status}`,
method: 'patch'
})
}
......@@ -18,9 +18,9 @@ export function listDeptExcludeChild(deptId) {
}
// 查询部门详细
export function getDept(deptId) {
export function getDept(deptBizId) {
return request({
url: '/system/dept/' + deptId,
url: '/user/api/sysDept/detail?deptBizId=' + deptBizId,
method: 'get'
})
}
......@@ -28,7 +28,7 @@ export function getDept(deptId) {
// 新增部门
export function addDept(data) {
return request({
url: '/system/dept',
url: '/user/api/sysDept/add',
method: 'post',
data: data
})
......@@ -46,7 +46,39 @@ export function updateDept(data) {
// 删除部门
export function delDept(deptId) {
return request({
url: '/system/dept/' + deptId,
url: '/user/api/sysDept/del?deptBizId=' + deptId,
method: 'delete'
})
}
\ No newline at end of file
}
// 编辑部门状态
export function deptStatusChange(deptBizId, status) {
return request({
url: `/user/api/sysDept/edit/status?deptBizId=${deptBizId}&status=${status}`,
method: 'patch'
})
}
// 编辑部门
export function editDept(data) {
return request({
url: '/user/api/sysDept/edit',
method: 'put',
data: data
})
}
//查询部门列表
export function deptList(data) {
return request({
url: '/user/api/sysDept/page',
method: 'post',
data: data
})
}
//获取公司列表
export function getAllCompanys(data) {
return request({
url: '/user/api/sysDept/company/page',
method: 'post',
data: data
})
}
......@@ -3,11 +3,15 @@
<template v-for="(item, index) in options">
<template v-if="values.includes(item.value)">
<span
v-if="(item.elTagType == 'default' || item.elTagType == '') && (item.elTagClass == '' || item.elTagClass == null)"
v-if="
(item.elTagType == 'default' || item.elTagType == '') &&
(item.elTagClass == '' || item.elTagClass == null)
"
:key="item.value"
:index="index"
:class="item.elTagClass"
>{{ item.label + " " }}</span>
>{{ item.label + ' ' }}</span
>
<el-tag
v-else
:disable-transitions="true"
......@@ -15,7 +19,8 @@
:index="index"
:type="item.elTagType"
:class="item.elTagClass"
>{{ item.label + " " }}</el-tag>
>{{ item.label + ' ' }}</el-tag
>
</template>
</template>
<template v-if="unmatch && showValue">
......@@ -32,30 +37,39 @@ const props = defineProps({
// 数据
options: {
type: Array,
default: null,
default: null
},
// 当前的值
value: [Number, String, Array],
// 当未找到匹配的数据时,显示value
showValue: {
type: Boolean,
default: true,
default: true
},
separator: {
type: String,
default: ",",
default: ','
}
})
const values = computed(() => {
if (props.value === null || typeof props.value === 'undefined' || props.value === '') return []
return Array.isArray(props.value) ? props.value.map(item => '' + item) : String(props.value).split(props.separator)
return Array.isArray(props.value)
? props.value.map(item => '' + item)
: String(props.value).split(props.separator)
})
const unmatch = computed(() => {
unmatchArray.value = []
// 没有value不显示
if (props.value === null || typeof props.value === 'undefined' || props.value === '' || !Array.isArray(props.options) || props.options.length === 0) return false
if (
props.value === null ||
typeof props.value === 'undefined' ||
props.value === '' ||
!Array.isArray(props.options) ||
props.options.length === 0
)
return false
// 传入值为数组
let unmatch = false // 添加一个标志来判断是否有未匹配项
values.value.forEach(item => {
......@@ -68,9 +82,9 @@ const unmatch = computed(() => {
})
function handleArray(array) {
if (array.length === 0) return ""
if (array.length === 0) return ''
return array.reduce((pre, cur) => {
return pre + " " + cur
return pre + ' ' + cur
})
}
</script>
......
......@@ -28,28 +28,20 @@
大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b>
</template>
<template v-if="fileType">
格式为 <b style="color: #f56c6c">{{ fileType.join("/") }}</b>
格式为 <b style="color: #f56c6c">{{ fileType.join('/') }}</b>
</template>
的文件
</div>
<el-dialog
v-model="dialogVisible"
title="预览"
width="800px"
append-to-body
>
<img
:src="dialogImageUrl"
style="display: block; max-width: 100%; margin: 0 auto"
/>
<el-dialog v-model="dialogVisible" title="预览" width="800px" append-to-body>
<img :src="dialogImageUrl" style="display: block; max-width: 100%; margin: 0 auto" />
</el-dialog>
</div>
</template>
<script setup>
import { getToken } from "@/utils/auth"
import { isExternal } from "@/utils/validate"
import { getToken } from '@/utils/auth'
import { isExternal } from '@/utils/validate'
import Sortable from 'sortablejs'
const props = defineProps({
......@@ -57,7 +49,7 @@ const props = defineProps({
// 上传接口地址
action: {
type: String,
default: "/common/upload"
default: '/common/upload'
},
// 上传携带的参数
data: {
......@@ -76,7 +68,7 @@ const props = defineProps({
// 文件类型, 例如['png', 'jpg', 'jpeg']
fileType: {
type: Array,
default: () => ["png", "jpg", "jpeg"]
default: () => ['png', 'jpg', 'jpeg']
},
// 是否显示提示
isShowTip: {
......@@ -99,44 +91,46 @@ const { proxy } = getCurrentInstance()
const emit = defineEmits()
const number = ref(0)
const uploadList = ref([])
const dialogImageUrl = ref("")
const dialogImageUrl = ref('')
const dialogVisible = ref(false)
const baseUrl = import.meta.env.VITE_APP_BASE_API
const uploadImgUrl = ref(import.meta.env.VITE_APP_BASE_API + props.action) // 上传的图片服务器地址
const headers = ref({ Authorization: "Bearer " + getToken() })
const headers = ref({ Authorization: 'Bearer ' + getToken() })
const fileList = ref([])
const showTip = computed(
() => props.isShowTip && (props.fileType || props.fileSize)
)
watch(() => props.modelValue, val => {
if (val) {
// 首先将值转为数组
const list = Array.isArray(val) ? val : props.modelValue.split(",")
// 然后将数组转为对象数组
fileList.value = list.map(item => {
if (typeof item === "string") {
if (item.indexOf(baseUrl) === -1 && !isExternal(item)) {
item = { name: baseUrl + item, url: baseUrl + item }
} else {
item = { name: item, url: item }
const showTip = computed(() => props.isShowTip && (props.fileType || props.fileSize))
watch(
() => props.modelValue,
val => {
if (val) {
// 首先将值转为数组
const list = Array.isArray(val) ? val : props.modelValue.split(',')
// 然后将数组转为对象数组
fileList.value = list.map(item => {
if (typeof item === 'string') {
if (item.indexOf(baseUrl) === -1 && !isExternal(item)) {
item = { name: baseUrl + item, url: baseUrl + item }
} else {
item = { name: item, url: item }
}
}
}
return item
})
} else {
fileList.value = []
return []
}
},{ deep: true, immediate: true })
return item
})
} else {
fileList.value = []
return []
}
},
{ deep: true, immediate: true }
)
// 上传前loading加载
function handleBeforeUpload(file) {
let isImg = false
if (props.fileType.length) {
let fileExtension = ""
if (file.name.lastIndexOf(".") > -1) {
fileExtension = file.name.slice(file.name.lastIndexOf(".") + 1)
let fileExtension = ''
if (file.name.lastIndexOf('.') > -1) {
fileExtension = file.name.slice(file.name.lastIndexOf('.') + 1)
}
isImg = props.fileType.some(type => {
if (file.type.indexOf(type) > -1) return true
......@@ -144,10 +138,10 @@ function handleBeforeUpload(file) {
return false
})
} else {
isImg = file.type.indexOf("image") > -1
isImg = file.type.indexOf('image') > -1
}
if (!isImg) {
proxy.$modal.msgError(`文件格式不正确,请上传${props.fileType.join("/")}图片格式文件!`)
proxy.$modal.msgError(`文件格式不正确,请上传${props.fileType.join('/')}图片格式文件!`)
return false
}
if (file.name.includes(',')) {
......@@ -161,7 +155,7 @@ function handleBeforeUpload(file) {
return false
}
}
proxy.$modal.loading("正在上传图片,请稍候...")
proxy.$modal.loading('正在上传图片,请稍候...')
number.value++
}
......@@ -173,7 +167,9 @@ function handleExceed() {
// 上传成功回调
function handleUploadSuccess(res, file) {
if (res.code === 200) {
uploadList.value.push({ name: res.fileName, url: res.fileName })
console.log('图片上传', res)
uploadList.value.push({ name: res.data.originalName, url: res.data.url })
uploadedSuccessfully()
} else {
number.value--
......@@ -189,7 +185,7 @@ function handleDelete(file) {
const findex = fileList.value.map(f => f.name).indexOf(file.name)
if (findex > -1 && uploadList.value.length === number.value) {
fileList.value.splice(findex, 1)
emit("update:modelValue", listToString(fileList.value))
emit('update:modelValue', listToString(fileList.value))
return false
}
}
......@@ -200,14 +196,14 @@ function uploadedSuccessfully() {
fileList.value = fileList.value.filter(f => f.url !== undefined).concat(uploadList.value)
uploadList.value = []
number.value = 0
emit("update:modelValue", listToString(fileList.value))
emit('update:modelValue', listToString(fileList.value))
proxy.$modal.closeLoading()
}
}
// 上传失败
function handleUploadError() {
proxy.$modal.msgError("上传图片失败")
proxy.$modal.msgError('上传图片失败')
proxy.$modal.closeLoading()
}
......@@ -219,14 +215,14 @@ function handlePictureCardPreview(file) {
// 对象转成指定字符串分隔
function listToString(list, separator) {
let strs = ""
separator = separator || ","
let strs = ''
separator = separator || ','
for (let i in list) {
if (undefined !== list[i].url && list[i].url.indexOf("blob:") !== 0) {
strs += list[i].url.replace(baseUrl, "") + separator
if (undefined !== list[i].url && list[i].url.indexOf('blob:') !== 0) {
strs += list[i].url.replace(baseUrl, '') + separator
}
}
return strs != "" ? strs.substr(0, strs.length - 1) : ""
return strs != '' ? strs.substr(0, strs.length - 1) : ''
}
// 初始化拖拽排序
......@@ -235,7 +231,7 @@ onMounted(() => {
nextTick(() => {
const element = proxy.$refs.imageUpload?.$el?.querySelector('.el-upload-list')
Sortable.create(element, {
onEnd: (evt) => {
onEnd: evt => {
const movedItem = fileList.value.splice(evt.oldIndex, 1)[0]
fileList.value.splice(evt.newIndex, 0, movedItem)
emit('update:modelValue', listToString(fileList.value))
......@@ -249,10 +245,10 @@ onMounted(() => {
<style scoped lang="scss">
// .el-upload--picture-card 控制加号部分
:deep(.hide .el-upload--picture-card) {
display: none;
display: none;
}
:deep(.el-upload.el-upload--picture-card.is-disabled) {
display: none !important;
}
</style>
\ No newline at end of file
}
</style>
<template>
<el-select
v-model="selectedValues"
multiple
collapse-tags
collapse-tags-tooltip
:placeholder="placeholder"
@remove-tag="handleRemoveTag"
@clear="handleClear"
>
<el-option :value="optionValue" style="height: auto; padding: 0">
<el-tree
ref="treeRef"
:data="treeData"
:props="treeProps"
:node-key="nodeKey"
:default-expand-all="defaultExpandAll"
:expand-on-click-node="false"
:check-strictly="checkStrictly"
show-checkbox
@check="handleTreeCheck"
>
<template #default="{ node, data }">
<span class="custom-tree-node">
<span v-if="showIcon && data.icon" :class="data.icon" style="margin-right: 6px"></span>
<span>{{ node.label }}</span>
</span>
</template>
</el-tree>
</el-option>
</el-select>
</template>
<script setup>
import { ref, watch, computed, onMounted } from 'vue'
const props = defineProps({
// 树形数据
treeData: {
type: Array,
default: () => []
},
// 树形配置
treeProps: {
type: Object,
default: () => ({
children: 'children',
label: 'label',
disabled: 'disabled'
})
},
// 节点唯一标识字段
nodeKey: {
type: String,
default: 'id'
},
// 是否默认展开所有节点
defaultExpandAll: {
type: Boolean,
default: false
},
// 是否严格遵守父子不互相关联
checkStrictly: {
type: Boolean,
default: false
},
// 是否显示图标
showIcon: {
type: Boolean,
default: false
},
// 选中的值
modelValue: {
type: Array,
default: () => []
},
// 占位符
placeholder: {
type: String,
default: '请选择'
}
})
const emit = defineEmits(['update:modelValue', 'change'])
const treeRef = ref(null)
const selectedValues = ref([])
const optionValue = ref([]) // 虚拟option值,用于el-select
// 初始化选中值
onMounted(() => {
selectedValues.value = [...props.modelValue]
if (treeRef.value) {
treeRef.value.setCheckedKeys(selectedValues.value)
}
})
// 监听外部modelValue变化
watch(
() => props.modelValue,
newVal => {
if (JSON.stringify(newVal) !== JSON.stringify(selectedValues.value)) {
selectedValues.value = [...newVal]
if (treeRef.value) {
treeRef.value.setCheckedKeys(selectedValues.value)
}
}
}
)
// 处理树节点选中事件
const handleTreeCheck = (node, treeCheckedStatus) => {
const checkedKeys = treeCheckedStatus.checkedKeys
selectedValues.value = checkedKeys
emit('update:modelValue', checkedKeys)
emit('change', checkedKeys)
}
// 处理移除标签事件
const handleRemoveTag = tag => {
if (treeRef.value) {
treeRef.value.setChecked(tag, false)
}
}
// 处理清空事件
const handleClear = () => {
if (treeRef.value) {
treeRef.value.setCheckedKeys([])
}
}
</script>
<style scoped>
.custom-tree-node {
flex: 1;
display: flex;
align-items: center;
font-size: 14px;
padding-right: 8px;
}
:deep(.el-select .el-select__tags) {
flex-wrap: nowrap;
overflow: hidden;
}
:deep(.el-tree) {
padding: 8px 12px;
max-height: 300px;
overflow-y: auto;
}
:deep(.el-tree-node__content) {
height: 34px;
}
</style>
<template>
<div class="navbar">
<hamburger id="hamburger-container" :is-active="appStore.sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" />
<breadcrumb v-if="!settingsStore.topNav" id="breadcrumb-container" class="breadcrumb-container" />
<hamburger
id="hamburger-container"
:is-active="appStore.sidebar.opened"
class="hamburger-container"
@toggleClick="toggleSideBar"
/>
<breadcrumb
v-if="!settingsStore.topNav"
id="breadcrumb-container"
class="breadcrumb-container"
/>
<top-nav v-if="settingsStore.topNav" id="topmenu-container" class="topmenu-container" />
<div class="right-menu">
<!-- 添加租户选择器 -->
<!-- <tenant-select class="right-menu-item hover-effect" v-if="userStore.tenants.length >= 1" />-->
<!-- <tenant-select class="right-menu-item hover-effect" v-if="userStore.tenants.length >= 1" />-->
<el-dropdown class="tenant-selector" @command="handleTenantChange">
<span class="el-dropdown-link">
{{ currentTenantName }}<el-icon class="el-icon--right"><arrow-down /></el-icon>
......@@ -14,9 +23,9 @@
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item
v-for="tenant in availableTenants"
:key="tenant.apiLoginTenantInfoResponse.tenantBizId"
:command="tenant"
v-for="tenant in availableTenants"
:key="tenant.apiLoginTenantInfoResponse.tenantBizId"
:command="tenant"
>
{{ tenant.apiLoginTenantInfoResponse.tenantName }}
</el-dropdown-item>
......@@ -26,13 +35,13 @@
<template v-if="appStore.device !== 'mobile'">
<header-search id="header-search" class="right-menu-item" />
<el-tooltip content="源码地址" effect="dark" placement="bottom">
<!-- <el-tooltip content="源码地址" effect="dark" placement="bottom">
<ruo-yi-git id="ruoyi-git" class="right-menu-item hover-effect" />
</el-tooltip>
</el-tooltip> -->
<el-tooltip content="文档地址" effect="dark" placement="bottom">
<!-- <el-tooltip content="文档地址" effect="dark" placement="bottom">
<ruo-yi-doc id="ruoyi-doc" class="right-menu-item hover-effect" />
</el-tooltip>
</el-tooltip> -->
<screenfull id="screenfull" class="right-menu-item hover-effect" />
......@@ -48,23 +57,31 @@
</el-tooltip>
</template>
<el-dropdown @command="handleCommand" class="avatar-container right-menu-item hover-effect" trigger="hover">
<el-dropdown
@command="handleCommand"
class="avatar-container right-menu-item hover-effect"
trigger="hover"
>
<div class="avatar-wrapper">
<img :src="userStore.avatar" class="user-avatar" />
<span class="user-nickname"> {{ userStore.nickName }} </span>
</div>
<template #dropdown>
<el-dropdown-menu>
<router-link to="/user/profile">
<!-- <router-link to="/user/profile">
<el-dropdown-item>个人中心</el-dropdown-item>
</router-link>
</router-link> -->
<el-dropdown-item divided command="logout">
<span>退出登录</span>
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
<div class="right-menu-item hover-effect setting" @click="setLayout" v-if="settingsStore.showSettings">
<div
class="right-menu-item hover-effect setting"
@click="setLayout"
v-if="settingsStore.showSettings"
>
<svg-icon icon-class="more-up" />
</div>
</div>
......@@ -98,9 +115,10 @@ const availableTenants = computed(() => {
// 添加空值检查
if (!userStore.tenants) return []
return userStore.tenants.filter(tenant =>
return userStore.tenants.filter(
tenant =>
// (tenant.apiLoginProjectInfoResponseList && tenant.apiLoginProjectInfoResponseList.length > 0) &&
(tenant.apiLoginTenantInfoResponse && tenant.apiLoginTenantInfoResponse.status === 1)
tenant.apiLoginTenantInfoResponse && tenant.apiLoginTenantInfoResponse.status === 1
)
})
......@@ -115,7 +133,8 @@ const currentTenantName = computed(() => {
})
// 切换租户处理
const handleTenantChange = (tenant) => {
const handleTenantChange = tenant => {
// 之前的逻辑
userStore.switchTenant(tenant)
}
......@@ -125,10 +144,10 @@ function toggleSideBar() {
function handleCommand(command) {
switch (command) {
case "setLayout":
case 'setLayout':
setLayout()
break
case "logout":
case 'logout':
logout()
break
default:
......@@ -141,11 +160,13 @@ function logout() {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
userStore.logOut().then(() => {
location.href = '/index'
})
.then(() => {
userStore.logOut().then(() => {
location.href = '/workbench'
})
})
}).catch(() => { })
.catch(() => {})
}
const emits = defineEmits(['setLayout'])
......@@ -158,7 +179,7 @@ function toggleTheme() {
}
</script>
<style lang='scss' scoped>
<style lang="scss" scoped>
.tenant-selector {
margin-left: 20px;
cursor: pointer;
......@@ -236,7 +257,7 @@ function toggleTheme() {
svg {
transition: transform 0.3s;
&:hover {
transform: scale(1.15);
}
......@@ -260,7 +281,7 @@ function toggleTheme() {
border-radius: 50%;
}
.user-nickname{
.user-nickname {
position: relative;
left: 5px;
bottom: 10px;
......@@ -278,7 +299,7 @@ function toggleTheme() {
}
}
//租户选择器样式
//租户选择器样式
//.tenant-select {
// margin-right: 10px;
// padding: 0 10px;
......
......@@ -14,7 +14,7 @@
</template>
<script setup>
import logo from '@/assets/logo/logo.png'
import logo from '@/assets/logo/companyLogo.png'
import useSettingsStore from '@/store/modules/settings'
import variables from '@/assets/styles/variables.module.scss'
......@@ -94,4 +94,4 @@ const getLogoTextColor = computed(() => {
}
}
}
</style>
\ No newline at end of file
</style>
......@@ -5,38 +5,39 @@
v-for="tag in visitedViews"
:key="tag.path"
:data-path="tag.path"
:class="{ 'active': isActive(tag), 'has-icon': tagsIcon }"
:class="{ active: isActive(tag), 'has-icon': tagsIcon }"
:to="{ path: tag.path, query: tag.query, fullPath: tag.fullPath }"
class="tags-view-item"
:style="activeStyle(tag)"
@click.middle="!isAffix(tag) ? closeSelectedTag(tag) : ''"
@contextmenu.prevent="openMenu(tag, $event)"
>
<svg-icon v-if="tagsIcon && tag.meta && tag.meta.icon && tag.meta.icon !== '#'" :icon-class="tag.meta.icon" />
<svg-icon
v-if="tagsIcon && tag.meta && tag.meta.icon && tag.meta.icon !== '#'"
:icon-class="tag.meta.icon"
/>
{{ tag.title }}
<span v-if="!isAffix(tag)" @click.prevent.stop="closeSelectedTag(tag)">
<close class="el-icon-close" style="width: 1em; height: 1em;vertical-align: middle;" />
<close class="el-icon-close" style="width: 1em; height: 1em; vertical-align: middle" />
</span>
</router-link>
</scroll-pane>
<ul v-show="visible" :style="{ left: left + 'px', top: top + 'px' }" class="contextmenu">
<li @click="refreshSelectedTag(selectedTag)">
<refresh-right style="width: 1em; height: 1em;" /> 刷新页面
<refresh-right style="width: 1em; height: 1em" /> 刷新页面
</li>
<li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)">
<close style="width: 1em; height: 1em;" /> 关闭当前
</li>
<li @click="closeOthersTags">
<circle-close style="width: 1em; height: 1em;" /> 关闭其他
<close style="width: 1em; height: 1em" /> 关闭当前
</li>
<li @click="closeOthersTags"><circle-close style="width: 1em; height: 1em" /> 关闭其他</li>
<li v-if="!isFirstView()" @click="closeLeftTags">
<back style="width: 1em; height: 1em;" /> 关闭左侧
<back style="width: 1em; height: 1em" /> 关闭左侧
</li>
<li v-if="!isLastView()" @click="closeRightTags">
<right style="width: 1em; height: 1em;" /> 关闭右侧
<right style="width: 1em; height: 1em" /> 关闭右侧
</li>
<li @click="closeAllTags(selectedTag)">
<circle-close style="width: 1em; height: 1em;" /> 全部关闭
<circle-close style="width: 1em; height: 1em" /> 全部关闭
</li>
</ul>
</div>
......@@ -64,13 +65,14 @@ const visitedViews = computed(() => useTagsViewStore().visitedViews)
const routes = computed(() => usePermissionStore().routes)
const theme = computed(() => useSettingsStore().theme)
const tagsIcon = computed(() => useSettingsStore().tagsIcon)
console.log('visitedViews', visitedViews.value)
watch(route, () => {
addTags()
moveToCurrentTag()
})
watch(visible, (value) => {
watch(visible, value => {
if (value) {
document.body.addEventListener('click', closeMenu)
} else {
......@@ -90,8 +92,8 @@ function isActive(r) {
function activeStyle(tag) {
if (!isActive(tag)) return {}
return {
"background-color": theme.value,
"border-color": theme.value
'background-color': theme.value,
'border-color': theme.value
}
}
......@@ -101,7 +103,10 @@ function isAffix(tag) {
function isFirstView() {
try {
return selectedTag.value.fullPath === '/index' || selectedTag.value.fullPath === visitedViews.value[1].fullPath
return (
selectedTag.value.fullPath === '/index' ||
selectedTag.value.fullPath === visitedViews.value[1].fullPath
)
} catch (err) {
return false
}
......@@ -143,7 +148,7 @@ function initTags() {
for (const tag of res) {
// Must have tag name
if (tag.name) {
useTagsViewStore().addVisitedView(tag)
useTagsViewStore().addVisitedView(tag)
}
}
}
......@@ -201,7 +206,7 @@ function closeLeftTags() {
}
function closeOthersTags() {
router.push(selectedTag.value).catch(() => { })
router.push(selectedTag.value).catch(() => {})
proxy.$tab.closeOtherPage(selectedTag.value).then(() => {
moveToCurrentTag()
})
......@@ -265,7 +270,7 @@ function handleScroll() {
width: 100%;
background: var(--tags-bg, #fff);
border-bottom: 1px solid var(--tags-item-border, #d8dce5);
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, .12), 0 0 3px 0 rgba(0, 0, 0, .04);
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12), 0 0 3px 0 rgba(0, 0, 0, 0.04);
.tags-view-wrapper {
.tags-view-item {
......@@ -324,7 +329,7 @@ function handleScroll() {
font-size: 12px;
font-weight: 400;
color: var(--tags-item-text, #333);
box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, .3);
box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, 0.3);
border: 1px solid var(--el-border-color-light, #e4e7ed);
li {
......@@ -350,11 +355,11 @@ function handleScroll() {
vertical-align: 2px;
border-radius: 50%;
text-align: center;
transition: all .3s cubic-bezier(.645, .045, .355, 1);
transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
transform-origin: 100% 50%;
&:before {
transform: scale(.6);
transform: scale(0.6);
display: inline-block;
vertical-align: -3px;
}
......
......@@ -48,7 +48,7 @@ export const constantRoutes = [
hidden: true
},
{
path: "/:pathMatch(.*)*",
path: '/:pathMatch(.*)*',
component: () => import('@/views/error/404'),
hidden: true
},
......@@ -70,7 +70,7 @@ export const constantRoutes = [
meta: { title: '工作台', icon: 'dashboard', affix: true }
}
]
},
}
// {
// path: '',
// component: Layout,
......@@ -198,7 +198,7 @@ const router = createRouter({
return savedPosition
}
return { top: 0 }
},
}
})
// 重置路由函数
......
......@@ -9,55 +9,54 @@ import useUserStore from '@/store/modules/user'
// 匹配views里面所有的.vue文件
const modules = import.meta.glob('./../../views/**/*.vue')
const usePermissionStore = defineStore(
'permission',
{
state: () => ({
routes: [],
addRoutes: [],
defaultRoutes: [],
topbarRouters: [],
sidebarRouters: []
}),
actions: {
setRoutes(routes) {
this.addRoutes = routes
this.routes = constantRoutes.concat(routes)
},
setDefaultRoutes(routes) {
this.defaultRoutes = constantRoutes.concat(routes)
},
setTopbarRoutes(routes) {
this.topbarRouters = routes
},
setSidebarRouters(routes) {
this.sidebarRouters = routes
},
generateRoutes() {
return new Promise(resolve => {
const userStore = useUserStore()
const tenantBizId = userStore.currentTenant.apiLoginTenantInfoResponse.tenantBizId || "tenant_1001"
getRouters(tenantBizId).then(res => {
const sdata = JSON.parse(JSON.stringify(res.data))
const rdata = JSON.parse(JSON.stringify(res.data))
const defaultData = JSON.parse(JSON.stringify(res.data))
const sidebarRoutes = filterAsyncRouter(sdata)
const rewriteRoutes = filterAsyncRouter(rdata, false, true)
const defaultRoutes = filterAsyncRouter(defaultData)
this.setRoutes(rewriteRoutes)
this.setSidebarRouters(constantRoutes.concat(sidebarRoutes))
this.setDefaultRoutes(sidebarRoutes)
this.setTopbarRoutes(defaultRoutes)
resolve(rewriteRoutes)
})
const usePermissionStore = defineStore('permission', {
state: () => ({
routes: [],
addRoutes: [],
defaultRoutes: [],
topbarRouters: [],
sidebarRouters: []
}),
actions: {
setRoutes(routes) {
this.addRoutes = routes
this.routes = constantRoutes.concat(routes)
},
setDefaultRoutes(routes) {
this.defaultRoutes = constantRoutes.concat(routes)
},
setTopbarRoutes(routes) {
this.topbarRouters = routes
},
setSidebarRouters(routes) {
this.sidebarRouters = routes
},
generateRoutes() {
return new Promise(resolve => {
const userStore = useUserStore()
const tenantBizId =
userStore.currentTenant.apiLoginTenantInfoResponse.tenantBizId || 'tenant_1001'
// debugger
getRouters(tenantBizId).then(res => {
const sdata = JSON.parse(JSON.stringify(res.data))
const rdata = JSON.parse(JSON.stringify(res.data))
const defaultData = JSON.parse(JSON.stringify(res.data))
const sidebarRoutes = filterAsyncRouter(sdata)
const rewriteRoutes = filterAsyncRouter(rdata, false, true)
const defaultRoutes = filterAsyncRouter(defaultData)
this.setRoutes(rewriteRoutes)
this.setSidebarRouters(constantRoutes.concat(sidebarRoutes))
this.setDefaultRoutes(sidebarRoutes)
this.setTopbarRoutes(defaultRoutes)
resolve(rewriteRoutes)
})
}
})
}
})
}
})
// export default usePermissionStore
......@@ -66,28 +65,30 @@ function filterAsyncRouter(asyncRouterMap, lastRouter = false, type = false) {
return asyncRouterMap.filter(route => {
// 确保路由有有效路径
if (!route.path || route.path.trim() === '') {
console.warn('忽略无效路由项(缺少路径):', route);
return false;
console.warn('忽略无效路由项(缺少路径):', route)
return false
}
// 只处理目录(1)和菜单(2)类型
if (route.menuType !== 1 && route.menuType !== 2) {
return false;
return false
}
// 创建必要的元信息
if (!route.meta) {
route.meta = {};
route.meta = {}
}
// 设置菜单标题
route.meta.title = route.menuName;
route.meta.icon = route.icon;
route.meta.isCache = route.isCache === 1;
route.meta.title = route.menuName
route.meta.icon = route.icon
route.meta.isCache = route.isCache === 1
route.name = route.routeName
//确保单子菜单的父菜单也显示
if (route.menuType === 1) {
route.alwaysShow = true; // 强制显示父菜单
route.alwaysShow = true // 强制显示父菜单
}
// 新增:添加标签页显示属性(关键修改)
......@@ -96,36 +97,36 @@ function filterAsyncRouter(asyncRouterMap, lastRouter = false, type = false) {
// 确保顶级菜单有布局组件
if (route.parentBizId === '0' && !route.component) {
route.component = 'Layout';
route.component = 'Layout'
}
// 组件映射处理
if (route.component) {
if (route.component === 'Layout') {
route.component = Layout;
route.component = Layout
} else if (route.component === 'ParentView') {
route.component = ParentView;
route.component = ParentView
} else if (route.component === 'InnerLink') {
route.component = InnerLink;
route.component = InnerLink
} else {
route.component = loadView(route.component);
route.component = loadView(route.component)
}
}
// 递归处理子路由
if (route.children && route.children.length) {
route.children = filterAsyncRouter(route.children, route, type);
route.children = filterAsyncRouter(route.children, route, type)
// 设置重定向到第一个子路由(对于目录类型)
if (route.menuType === 1 && route.children.length > 0) {
route.redirect = route.children[0].path;
route.redirect = route.children[0].path
}
} else {
delete route.children;
delete route.children
}
return true;
});
return true
})
}
// // 遍历后台传来的路由字符串,转换为组件对象
// function filterAsyncRouter(asyncRouterMap, lastRouter = false, type = false) {
......@@ -185,7 +186,7 @@ export function filterDynamicRoutes(routes) {
return res
}
export const loadView = (view) => {
export const loadView = view => {
let res
for (const path in modules) {
const dir = path.split('views/')[1].split('.vue')[0]
......
......@@ -20,10 +20,7 @@
@click="goTarget('https://gitee.com/y_project/RuoYi-Vue')"
>访问码云</el-button
>
<el-button
icon="HomeFilled"
plain
@click="goTarget('http://ruoyi.vip')"
<el-button icon="HomeFilled" plain @click="goTarget('http://ruoyi.vip')"
>访问主页</el-button
>
</p>
......@@ -83,22 +80,20 @@
<p>
<i class="el-icon-user-solid"></i> QQ群:<s> 满937441 </s> <s> 满887144332 </s>
<s> 满180251782 </s> <s> 满104180207 </s> <s> 满186866453 </s> <s> 满201396349 </s>
<s> 满101456076 </s> <s> 满101539465 </s> <s> 满264312783 </s> <s> 满167385320 </s>
<s> 满104748341 </s> <s> 满160110482 </s> <s> 满170801498 </s> <s> 满108482800 </s>
<s> 满101046199 </s> <s> 满136919097 </s> <s> 满143961921 </s> <s> 满174951577 </s>
<s> 满101456076 </s> <s> 满101539465 </s> <s> 满264312783 </s> <s> 满167385320 </s>
<s> 满104748341 </s> <s> 满160110482 </s> <s> 满170801498 </s> <s> 满108482800 </s>
<s> 满101046199 </s> <s> 满136919097 </s> <s> 满143961921 </s> <s> 满174951577 </s>
<s> 满161281055 </s> <s> 满138988063 </s> <s> 满151450850 </s> <s> 满224622315 </s>
<s> 满287842588 </s> <s> 满187944233 </s> <s> 满228578329 </s> <a href="http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=GsOo-OLz53J8y_9TPoO6XXSGNRTgbFxA&authKey=R7Uy%2Feq%2BZsoKNqHvRKhiXpypW7DAogoWapOawUGHokJSBIBIre2%2FoiAZeZBSLuBc&noverify=0&group_code=191164766" target="_blank">191164766</a>
</p>
<p>
<i class="el-icon-chat-dot-round"></i> 微信:<a
href="javascript:;"
>/ *若依</a
<s> 满287842588 </s> <s> 满187944233 </s> <s> 满228578329 </s>
<a
href="http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=GsOo-OLz53J8y_9TPoO6XXSGNRTgbFxA&authKey=R7Uy%2Feq%2BZsoKNqHvRKhiXpypW7DAogoWapOawUGHokJSBIBIre2%2FoiAZeZBSLuBc&noverify=0&group_code=191164766"
target="_blank"
>191164766</a
>
</p>
<p><i class="el-icon-chat-dot-round"></i> 微信:<a href="javascript:;">/ *若依</a></p>
<p>
<i class="el-icon-money"></i> 支付宝:<a
href="javascript:;"
class="支付宝信息"
<i class="el-icon-money"></i> 支付宝:<a href="javascript:;" class="支付宝信息"
>/ *若依</a
>
</p>
......@@ -878,9 +873,7 @@
<li>调整表头固定列默认样式</li>
<li>代码生成模板调整,字段为String并且必填则加空串条件</li>
<li>代码生成字典Integer/Long使用parseInt</li>
<li>
修复dict_sort不可update为0的问题&查询返回增加dict_sort升序排序
</li>
<li>修复dict_sort不可update为0的问题&查询返回增加dict_sort升序排序</li>
<li>修正岗位导出权限注解</li>
<li>禁止加密密文返回前端</li>
<li>修复代码生成页面中的查询条件创建时间未生效的问题</li>
......@@ -1042,11 +1035,7 @@
</div>
</template>
<div class="body">
<img
src="@/assets/images/pay.png"
alt="donate"
style="width:100%"
/>
<img src="@/assets/images/pay.png" alt="donate" style="width: 100%" />
<span style="display: inline-block; height: 30px; line-height: 30px"
>你可以请作者喝杯咖啡表示鼓励</span
>
......@@ -1088,7 +1077,7 @@ function goTarget(url) {
margin: 0;
}
font-family: "open sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
font-family: 'open sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
font-size: 13px;
color: #676a6c;
overflow-x: hidden;
......@@ -1128,4 +1117,3 @@ function goTarget(url) {
}
}
</style>
......@@ -10,7 +10,9 @@
auto-complete="off"
placeholder="账号"
>
<template #prefix><svg-icon icon-class="user" class="el-input__icon input-icon" /></template>
<template #prefix
><svg-icon icon-class="user" class="el-input__icon input-icon"
/></template>
</el-input>
</el-form-item>
<el-form-item prop="password">
......@@ -22,10 +24,12 @@
placeholder="密码"
@keyup.enter="handleLogin"
>
<template #prefix><svg-icon icon-class="password" class="el-input__icon input-icon" /></template>
<template #prefix
><svg-icon icon-class="password" class="el-input__icon input-icon"
/></template>
</el-input>
</el-form-item>
<el-form-item prop="code" v-if="captchaEnabled">
<!-- <el-form-item prop="code" v-if="captchaEnabled">
<el-input
v-model="loginForm.code"
size="large"
......@@ -39,20 +43,22 @@
<div class="login-code">
<img :src="codeUrl" @click="getCode" class="login-code-img"/>
</div>
</el-form-item>
<el-checkbox v-model="loginForm.rememberMe" style="margin:0px 0px 25px 0px;">记住密码</el-checkbox>
<el-form-item style="width:100%;">
</el-form-item> -->
<el-checkbox v-model="loginForm.rememberMe" style="margin: 0px 0px 25px 0px"
>记住密码</el-checkbox
>
<el-form-item style="width: 100%">
<el-button
:loading="loading"
size="large"
type="primary"
style="width:100%;"
style="width: 100%"
@click.prevent="handleLogin"
>
<span v-if="!loading">登 录</span>
<span v-else>登 录 中...</span>
</el-button>
<div style="float: right;" v-if="register">
<div style="float: right" v-if="register">
<router-link class="link-type" :to="'/register'">立即注册</router-link>
</div>
</el-form-item>
......@@ -65,9 +71,9 @@
</template>
<script setup>
import { getCodeImg } from "@/api/login"
import Cookies from "js-cookie"
import { encrypt, decrypt } from "@/utils/jsencrypt"
import { getCodeImg } from '@/api/login'
import Cookies from 'js-cookie'
import { encrypt, decrypt } from '@/utils/jsencrypt'
import useUserStore from '@/store/modules/user'
const title = import.meta.env.VITE_APP_TITLE
......@@ -77,20 +83,20 @@ const router = useRouter()
const { proxy } = getCurrentInstance()
const loginForm = ref({
username: "zs",
password: "123",
username: 'zs',
password: '123',
rememberMe: false,
code: "",
uuid: ""
code: '',
uuid: ''
})
const loginRules = {
username: [{ required: true, trigger: "blur", message: "请输入您的账号" }],
password: [{ required: true, trigger: "blur", message: "请输入您的密码" }],
code: [{ required: true, trigger: "change", message: "请输入验证码" }]
username: [{ required: true, trigger: 'blur', message: '请输入您的账号' }],
password: [{ required: true, trigger: 'blur', message: '请输入您的密码' }]
// code: [{ required: true, trigger: "change", message: "请输入验证码" }]
}
const codeUrl = ref("")
const codeUrl = ref('')
const loading = ref(false)
// 验证码开关
const captchaEnabled = ref(true)
......@@ -98,9 +104,13 @@ const captchaEnabled = ref(true)
const register = ref(false)
const redirect = ref(undefined)
watch(route, (newRoute) => {
watch(
route,
newRoute => {
redirect.value = newRoute.query && newRoute.query.redirect
}, { immediate: true })
},
{ immediate: true }
)
function handleLogin() {
proxy.$refs.loginRef.validate(valid => {
......@@ -108,50 +118,53 @@ function handleLogin() {
loading.value = true
// 勾选了需要记住密码设置在 cookie 中设置记住用户名和密码
if (loginForm.value.rememberMe) {
Cookies.set("username", loginForm.value.username, { expires: 30 })
Cookies.set("password", encrypt(loginForm.value.password), { expires: 30 })
Cookies.set("rememberMe", loginForm.value.rememberMe, { expires: 30 })
Cookies.set('username', loginForm.value.username, { expires: 30 })
Cookies.set('password', encrypt(loginForm.value.password), { expires: 30 })
Cookies.set('rememberMe', loginForm.value.rememberMe, { expires: 30 })
} else {
// 否则移除
Cookies.remove("username")
Cookies.remove("password")
Cookies.remove("rememberMe")
Cookies.remove('username')
Cookies.remove('password')
Cookies.remove('rememberMe')
}
// 调用action的登录方法
userStore.login(loginForm.value).then(() => {
const query = route.query
const otherQueryParams = Object.keys(query).reduce((acc, cur) => {
if (cur !== "redirect") {
acc[cur] = query[cur]
}
return acc
}, {})
router.push({ path: redirect.value || "/", query: otherQueryParams })
}).catch(() => {
loading.value = false
// 重新获取验证码
if (captchaEnabled.value) {
getCode()
}
})
userStore
.login(loginForm.value)
.then(() => {
const query = route.query
const otherQueryParams = Object.keys(query).reduce((acc, cur) => {
if (cur !== 'redirect') {
acc[cur] = query[cur]
}
return acc
}, {})
router.push({ path: redirect.value || '/', query: otherQueryParams })
})
.catch(() => {
loading.value = false
// 重新获取验证码
// if (captchaEnabled.value) {
// getCode()
// }
})
}
})
}
function getCode() {
const getCode = () => {
getCodeImg().then(res => {
captchaEnabled.value = res.captchaEnabled === undefined ? true : res.captchaEnabled
if (captchaEnabled.value) {
codeUrl.value = "data:image/gif;base64," + res.img
codeUrl.value = 'data:image/gif;base64,' + res.img
loginForm.value.uuid = res.uuid
}
})
}
function getCookie() {
const username = Cookies.get("username")
const password = Cookies.get("password")
const rememberMe = Cookies.get("rememberMe")
const username = Cookies.get('username')
const password = Cookies.get('password')
const rememberMe = Cookies.get('rememberMe')
loginForm.value = {
username: username === undefined ? loginForm.value.username : username,
password: password === undefined ? loginForm.value.password : decrypt(password),
......@@ -159,17 +172,17 @@ function getCookie() {
}
}
getCode()
// getCode()
getCookie()
</script>
<style lang='scss' scoped>
<style lang="scss" scoped>
.login {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
background-image: url("../assets/images/login-background.jpg");
background-image: url('../assets/images/login-background.jpg');
background-size: cover;
}
.title {
......
......@@ -336,8 +336,6 @@ function handleDelete(row) {
/** 角色状态修改 */
function handleStatusChange(row) {
console.log('row', row.status)
const newStatus = row.status === 0 ? 0 : 1 // 获取切换后的新状态
const text = newStatus === 0 ? '停用' : '启用' // 根据新状态显示文本
console.log('newStatus', newStatus)
......
<template>
<div class="app-card" @click="handleClick">
<div class="app-icon">
<img :src="project.logoUrl" alt="应用图标" v-if="project.logoUrl"/>
<img :src="project.logoUrl" alt="应用图标" v-if="project.logoUrl" />
<div class="default-icon" v-else>{{ appName.substring(0, 2) }}</div>
</div>
<div class="app-name">{{ appName }}</div>
......@@ -11,6 +11,8 @@
<script setup>
import { computed } from 'vue'
import { useRouter } from 'vue-router'
import { getVisitPermission } from '@/api/common'
import { getToken } from '@/utils/auth'
const props = defineProps({
project: {
......@@ -23,28 +25,41 @@ const router = useRouter()
const appName = computed(() => props.project.projectName)
const handleClick = () => {
// 记录最近使用的应用
const recentApps = JSON.parse(localStorage.getItem('recentApps') || '[]')
const newRecent = [
props.project,
...recentApps.filter(app => app.projectBizId !== props.project.projectBizId)
].slice(0, 5)
localStorage.setItem('recentApps', JSON.stringify(newRecent))
console.log('点击了应用卡片', props.project)
getVisitPermission(props.project.projectBizId).then(response => {
if (response.code === 200) {
// 有权限访问项目,进行跳转
// 记录最近使用的应用
const recentApps = JSON.parse(localStorage.getItem('recentApps') || '[]')
const newRecent = [
props.project,
...recentApps.filter(app => app.projectBizId !== props.project.projectBizId)
].slice(0, 5)
localStorage.setItem('recentApps', JSON.stringify(newRecent))
// 根据 isIn 字段决定跳转逻辑
if (props.project.isIn === 0 && props.project.projectUrl) {
// 外部跳转
window.open(props.project.projectUrl, '_blank')
} else {
// 内部跳转
router.push({
path: '/app/dashboard',
query: {
projectBizId: props.project.projectBizId,
projectName: props.project.projectName
// 根据 isIn 字段决定跳转逻辑
if (props.project.isIn === 0 && props.project.projectUrl) {
let newUrl = `${props.project.projectUrl}?projectBizId=${
props.project.projectBizId
}&tenantBizId=${props.project.tenantBizId}&token=${getToken()}`
// 外部跳转
window.open(newUrl, '_blank')
} else {
// 内部跳转
router.push({
path: '/app/dashboard',
query: {
projectBizId: props.project.projectBizId,
projectName: props.project.projectName
}
})
}
})
}
} else {
// 没访问权限提示信息
proxy.$modal.msgError(response.msg)
}
})
return
}
</script>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment