Commit 7d82bc09 by yuzhenWang

添加保险产品

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