34 Commits

Author SHA1 Message Date
fa8f650aa1 Merge branch 'gitee-master' into feature-project
# Conflicts:
#	README.md
2024-11-18 08:54:42 +08:00
芋道源码
1c23298d19 !578 【优化】添加自定义指令消除IDE警告
Merge pull request !578 from jinmh/master
2024-11-09 11:02:53 +00:00
jinmh716
8a97a33a29 【优化】添加自定义指令消除IDE警告 2024-11-05 17:30:23 +08:00
芋道源码
bf87c46d0f !574 【修复】开发模式下从“同时使用了用户信息和权限判断”的页面退出登录时异常问题
Merge pull request !574 from 半栈幼儿员/hotfix/user
2024-11-02 02:41:02 +00:00
preschooler
9b290ae3ce 🐞 fix:修复从“同时使用了用户信息和权限判断”的页面退出登录时异常问题 2024-10-29 12:35:44 +08:00
63fee3b541 Merge branch 'gitee-master' into feature-project 2024-10-28 10:40:13 +08:00
YunaiV
458242a27b README 更新:单体、微服务的地址 2024-10-28 09:56:55 +08:00
YunaiV
cf200b2618 README 更新:单体、微服务的地址 2024-10-28 09:54:08 +08:00
芋道源码
c1924d566f !570 【新增】TagsView 支持多个 path 相同但 fullPath 不相同情况。
Merge pull request !570 from 半栈幼儿员/hotfix/tagsView
2024-10-27 09:29:03 +00:00
芋道源码
b4139676f3 !571 【优化】@import 修改为 @use 以应对 sass 升级弃用 @import。
Merge pull request !571 from 半栈幼儿员/hotfix/sass
2024-10-27 08:42:32 +00:00
芋道源码
92f4160fe1 !572 修复:将超级管理员的角色code由admin改为super_admin
Merge pull request !572 from ZG4vin/master
2024-10-27 08:40:35 +00:00
YunaiV
c1a2228022 Merge branch 'master' of https://github.com/yudaocode/yudao-ui-admin-vue3
# Conflicts:
#	src/utils/is.ts
2024-10-27 16:40:00 +08:00
芋道源码
71a2fddb1b !568 修复hash路由无法跳转
Merge pull request !568 from hecongyuan/master
2024-10-27 08:37:35 +00:00
芋道源码
8bdf60c886 !573 【修复】修复退出登录后依旧在轮询消息未读数,导致反复弹窗。
Merge pull request !573 from 半栈幼儿员/hotfix/message
2024-10-27 08:36:40 +00:00
芋道源码
38360eef12 Merge pull request #95 from hecongyuan/master
修复hash路由无法跳转的问题
2024-10-27 16:25:53 +08:00
preschooler
17225ef3df 🐞 fix:修复退出登录后依旧在轮询消息未读数,导致反复弹窗。 2024-10-25 10:11:42 +08:00
ZG4vin
57ab876886 将超级管理员的角色code由admin改为super_admin 2024-10-24 17:48:35 +08:00
preschooler
8a8ae557f7 🐞 fix:@import 修改为 @use 以应对 sass 升级弃用 @import。 2024-10-23 11:01:23 +08:00
preschooler
a401d8ede4 feat:TagsView 支持多个 path 相同但 fullPath 不相同情况。 2024-10-22 17:22:18 +08:00
hecongyuan
3859a48825 修复hash路由无法跳转的问题 2024-10-21 17:10:36 +08:00
hecongyuan
0a4a9e0e55 修复hash路由无法跳转的问题 2024-10-21 17:05:05 +08:00
芋道源码
a31bafbb4a !566 【优化】文章列表显示ID方便构造链接,调整退款状态列宽显示完整
Merge pull request !566 from 杨宇庆/N/A
2024-10-16 11:27:58 +00:00
杨宇庆
10e432243e 【优化】文章列表显示ID方便构造链接,调整退款状态列宽显示完整
Signed-off-by: 杨宇庆 <hiyyq@qq.com>
2024-10-15 04:46:34 +00:00
583ce6d661 [fix] 更改描述 2024-10-14 15:09:13 +08:00
52a4cc210c Merge branch 'gitee-master' into feature-project
# Conflicts:
#	src/views/bpm/processInstance/detail/index.vue
2024-10-14 11:08:39 +08:00
YunaiV
5ef5ee6e14 【功能修复】工作流:业务表单 + 字段可编辑场景,审批、不审批点击没效果 2024-10-13 16:45:19 +08:00
YunaiV
2aefcd9070 【升级】vue from 3.4.21 to 3.5.12 2024-10-12 20:11:20 +08:00
YunaiV
dad97e2f17 【修复】工作流:流程实例的查询界面,缺少搜索、重置按钮 2024-10-12 20:09:01 +08:00
芋道源码
22e425208c !564 【升级插件】升级 form-create 插件版本
Merge pull request !564 from 半栈幼儿员/hotfix/form-create
2024-10-12 11:59:53 +00:00
芋道源码
77e8827f8b !562 【修复】修复菜单搜索点击输入框会折叠问题
Merge pull request !562 from 半栈幼儿员/hotfix/search
2024-10-12 11:56:31 +00:00
preschooler
c828517c55 🎈 perf:升级 form-create 插件版本 2024-10-10 16:25:09 +08:00
preschooler
2ff9904f63 🐞 fix:初始化 form-create 配置,修复“字段 ID”不可修改问题。 2024-10-10 16:19:05 +08:00
preschooler
fe21db3704 🐞 fix:修复因缺失引入 element plus 组件导致 form-create 表单设计器部分功能缺失。 2024-10-10 14:03:20 +08:00
preschooler
abcecc92c5 🐞 fix:修复菜单搜索点击输入框会折叠问题 2024-10-10 10:48:14 +08:00
28 changed files with 553 additions and 290 deletions

View File

@@ -26,8 +26,8 @@
}, },
"dependencies": { "dependencies": {
"@element-plus/icons-vue": "^2.1.0", "@element-plus/icons-vue": "^2.1.0",
"@form-create/designer": "^3.1.3", "@form-create/designer": "^3.2.6",
"@form-create/element-ui": "^3.1.24", "@form-create/element-ui": "^3.2.11",
"@iconify/iconify": "^3.1.1", "@iconify/iconify": "^3.1.1",
"@microsoft/fetch-event-source": "^2.0.1", "@microsoft/fetch-event-source": "^2.0.1",
"@videojs-player/vue": "^1.0.0", "@videojs-player/vue": "^1.0.0",
@@ -67,7 +67,7 @@
"steady-xml": "^0.1.0", "steady-xml": "^0.1.0",
"url": "^0.11.3", "url": "^0.11.3",
"video.js": "^7.21.5", "video.js": "^7.21.5",
"vue": "3.4.21", "vue": "3.5.12",
"vue-dompurify-html": "^4.1.4", "vue-dompurify-html": "^4.1.4",
"vue-i18n": "9.10.2", "vue-i18n": "9.10.2",
"vue-router": "^4.3.0", "vue-router": "^4.3.0",
@@ -143,6 +143,7 @@
"url": "https://gitee.com/yudaocode/yudao-ui-admin-vue3/issues" "url": "https://gitee.com/yudaocode/yudao-ui-admin-vue3/issues"
}, },
"homepage": "https://gitee.com/yudaocode/yudao-ui-admin-vue3", "homepage": "https://gitee.com/yudaocode/yudao-ui-admin-vue3",
"web-types": "./web-types.json",
"engines": { "engines": {
"node": ">= 16.0.0", "node": ">= 16.0.0",
"pnpm": ">=8.6.0" "pnpm": ">=8.6.0"

492
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -20,6 +20,7 @@
<div v-else class="custom-hover" @click.stop="showTopSearch = !showTopSearch"> <div v-else class="custom-hover" @click.stop="showTopSearch = !showTopSearch">
<Icon icon="ep:search" /> <Icon icon="ep:search" />
<el-select <el-select
@click.stop
filterable filterable
:reserve-keyword="false" :reserve-keyword="false"
remote remote

View File

@@ -5,7 +5,7 @@ $--color-danger: #ff4d4f;
/* 改变 icon 字体路径变量,必需 */ /* 改变 icon 字体路径变量,必需 */
$--font-path: '~element-ui/lib/theme-chalk/fonts'; $--font-path: '~element-ui/lib/theme-chalk/fonts';
@import '~element-ui/packages/theme-chalk/src/index'; @use '~element-ui/packages/theme-chalk/src/index';
.el-table td, .el-table td,
.el-table th { .el-table th {

View File

@@ -1,2 +1,2 @@
@import './process-designer.scss'; @use './process-designer.scss';
@import './process-panel.scss'; @use './process-panel.scss';

View File

@@ -1,6 +1,6 @@
@import 'bpmn-js-token-simulation/assets/css/bpmn-js-token-simulation.css'; @use 'bpmn-js-token-simulation/assets/css/bpmn-js-token-simulation.css';
@import 'bpmn-js-token-simulation/assets/css/font-awesome.min.css'; @use 'bpmn-js-token-simulation/assets/css/font-awesome.min.css';
@import 'bpmn-js-token-simulation/assets/css/normalize.css'; @use 'bpmn-js-token-simulation/assets/css/normalize.css';
// 边框被 token-simulation 样式覆盖了 // 边框被 token-simulation 样式覆盖了
.djs-palette { .djs-palette {

View File

@@ -8,7 +8,8 @@ export function hasPermi(app: App<Element>) {
const { wsCache } = useCache() const { wsCache } = useCache()
const { value } = binding const { value } = binding
const all_permission = '*:*:*' const all_permission = '*:*:*'
const permissions = wsCache.get(CACHE_KEY.USER).permissions const userInfo = wsCache.get(CACHE_KEY.USER)
const permissions = userInfo?.permissions || []
if (value && value instanceof Array && value.length > 0) { if (value && value instanceof Array && value.length > 0) {
const permissionFlag = value const permissionFlag = value

View File

@@ -7,8 +7,9 @@ export function hasRole(app: App<Element>) {
app.directive('hasRole', (el, binding) => { app.directive('hasRole', (el, binding) => {
const { wsCache } = useCache() const { wsCache } = useCache()
const { value } = binding const { value } = binding
const super_admin = 'admin' const super_admin = 'super_admin'
const roles = wsCache.get(CACHE_KEY.USER).roles const userInfo = wsCache.get(CACHE_KEY.USER)
const roles = userInfo?.roles || []
if (value && value instanceof Array && value.length > 0) { if (value && value instanceof Array && value.length > 0) {
const roleFlag = value const roleFlag = value

View File

@@ -1,10 +1,12 @@
<script lang="ts" setup> <script lang="ts" setup>
import { formatDate } from '@/utils/formatTime' import { formatDate } from '@/utils/formatTime'
import * as NotifyMessageApi from '@/api/system/notify/message' import * as NotifyMessageApi from '@/api/system/notify/message'
import { useUserStoreWithOut } from '@/store/modules/user'
defineOptions({ name: 'Message' }) defineOptions({ name: 'Message' })
const { push } = useRouter() const { push } = useRouter()
const userStore = useUserStoreWithOut()
const activeName = ref('notice') const activeName = ref('notice')
const unreadCount = ref(0) // 未读消息数量 const unreadCount = ref(0) // 未读消息数量
const list = ref<any[]>([]) // 消息列表 const list = ref<any[]>([]) // 消息列表
@@ -37,7 +39,11 @@ onMounted(() => {
// 轮询刷新小红点 // 轮询刷新小红点
setInterval( setInterval(
() => { () => {
getUnreadCount() if (userStore.getIsSetUser) {
getUnreadCount()
} else {
unreadCount.value = 0
}
}, },
1000 * 60 * 2 1000 * 60 * 2
) )

View File

@@ -127,12 +127,8 @@ const toLastView = () => {
const moveToCurrentTag = async () => { const moveToCurrentTag = async () => {
await nextTick() await nextTick()
for (const v of unref(visitedViews)) { for (const v of unref(visitedViews)) {
if (v.fullPath === unref(currentRoute).path) { if (v.fullPath === unref(currentRoute).fullPath) {
moveToTarget(v) moveToTarget(v)
if (v.fullPath !== unref(currentRoute).fullPath) {
tagsViewStore.updateVisitedView(unref(currentRoute))
}
break break
} }
} }
@@ -207,7 +203,7 @@ const moveToTarget = (currentTag: RouteLocationNormalizedLoaded) => {
// 是否是当前tag // 是否是当前tag
const isActive = (route: RouteLocationNormalizedLoaded): boolean => { const isActive = (route: RouteLocationNormalizedLoaded): boolean => {
return route.path === unref(currentRoute).path return route.fullPath === unref(currentRoute).fullPath
} }
// 所有右键菜单组件的元素 // 所有右键菜单组件的元素
@@ -373,7 +369,10 @@ watch(
:size="12" :size="12"
class="mr-5px" class="mr-5px"
/> />
{{ t(item?.meta?.title as string) }} {{
t(item?.meta?.title as string) +
(item?.meta?.titleSuffix ? ` (${item?.meta?.titleSuffix})` : '')
}}
<Icon <Icon
:class="`${prefixCls}__item--close`" :class="`${prefixCls}__item--close`"
:size="12" :size="12"

View File

@@ -1,7 +1,37 @@
import type { App } from 'vue' import type { App } from 'vue'
// 👇使用 form-create 需额外全局引入 element plus 组件 // 👇使用 form-create 需额外全局引入 element plus 组件
import { import {
// ElAutocomplete,
// ElButton,
// ElCascader,
// ElCheckbox,
// ElCheckboxButton,
// ElCheckboxGroup,
// ElCol,
// ElColorPicker,
// ElDatePicker,
// ElDialog,
// ElForm,
// ElInput,
// ElInputNumber,
// ElPopover,
// ElRadio,
// ElRadioButton,
// ElRadioGroup,
// ElRate,
// ElRow,
// ElSelect,
// ElSlider,
// ElSwitch,
// ElTimePicker,
// ElTooltip,
// ElTree,
// ElUpload,
// ElIcon,
// ElProgress,
// 以上会由 @form-create/element-ui/auto-import 自动引入
ElAlert, ElAlert,
ElTransfer,
ElAside, ElAside,
ElContainer, ElContainer,
ElDivider, ElDivider,
@@ -12,7 +42,18 @@ import {
ElTableColumn, ElTableColumn,
ElTabPane, ElTabPane,
ElTabs, ElTabs,
ElTransfer ElDropdown,
ElDropdownMenu,
ElDropdownItem,
ElBadge,
ElTag,
ElText,
ElMenu,
ElMenuItem,
ElFooter,
ElMessage
// ElFormItem,
// ElOption
} from 'element-plus' } from 'element-plus'
import FcDesigner from '@form-create/designer' import FcDesigner from '@form-create/designer'
import formCreate from '@form-create/element-ui' import formCreate from '@form-create/element-ui'
@@ -41,18 +82,30 @@ const ApiSelect = useApiSelect({
}) })
const components = [ const components = [
ElAlert,
ElTransfer,
ElAside, ElAside,
ElPopconfirm,
ElHeader,
ElMain,
ElContainer, ElContainer,
ElDivider, ElDivider,
ElTransfer, ElHeader,
ElAlert, ElMain,
ElTabs, ElPopconfirm,
ElTable, ElTable,
ElTableColumn, ElTableColumn,
ElTabPane, ElTabPane,
ElTabs,
ElDropdown,
ElDropdownMenu,
ElDropdownItem,
ElBadge,
ElTag,
ElText,
ElMenu,
ElMenuItem,
ElFooter,
ElMessage,
// ElFormItem,
// ElOption,
UploadImg, UploadImg,
UploadImgs, UploadImgs,
UploadFile, UploadFile,

View File

@@ -35,8 +35,9 @@ export const usePermissionStore = defineStore('permission', {
return new Promise<void>(async (resolve) => { return new Promise<void>(async (resolve) => {
// 获得菜单列表它在登录的时候setUserInfoAction 方法中已经进行获取 // 获得菜单列表它在登录的时候setUserInfoAction 方法中已经进行获取
let res: AppCustomRouteRecordRaw[] = [] let res: AppCustomRouteRecordRaw[] = []
if (wsCache.get(CACHE_KEY.ROLE_ROUTERS)) { const roleRouters = wsCache.get(CACHE_KEY.ROLE_ROUTERS)
res = wsCache.get(CACHE_KEY.ROLE_ROUTERS) as AppCustomRouteRecordRaw[] if (roleRouters) {
res = roleRouters as AppCustomRouteRecordRaw[]
} }
const routerMap: AppRouteRecordRaw[] = generateRoute(res) const routerMap: AppRouteRecordRaw[] = generateRoute(res)
// 动态路由404一定要放到最后面 // 动态路由404一定要放到最后面

View File

@@ -31,13 +31,27 @@ export const useTagsViewStore = defineStore('tagsView', {
}, },
// 新增tag // 新增tag
addVisitedView(view: RouteLocationNormalizedLoaded) { addVisitedView(view: RouteLocationNormalizedLoaded) {
if (this.visitedViews.some((v) => v.path === view.path)) return if (this.visitedViews.some((v) => v.fullPath === view.fullPath)) return
if (view.meta?.noTagsView) return if (view.meta?.noTagsView) return
this.visitedViews.push( const visitedView = Object.assign({}, view, { title: view.meta?.title || 'no-name' })
Object.assign({}, view, {
title: view.meta?.title || 'no-name' if (visitedView.meta) {
const titleSuffixList: string[] = []
this.visitedViews.forEach((v) => {
if (v.path === visitedView.path && v.meta?.title === visitedView.meta?.title) {
titleSuffixList.push(v.meta?.titleSuffix || '1')
}
}) })
) if (titleSuffixList.length) {
let titleSuffix = 1
while (titleSuffixList.includes(`${titleSuffix}`)) {
titleSuffix += 1
}
visitedView.meta.titleSuffix = titleSuffix === 1 ? undefined : `${titleSuffix}`
}
}
this.visitedViews.push(visitedView)
}, },
// 新增缓存 // 新增缓存
addCachedView() { addCachedView() {
@@ -63,7 +77,7 @@ export const useTagsViewStore = defineStore('tagsView', {
// 删除tag // 删除tag
delVisitedView(view: RouteLocationNormalizedLoaded) { delVisitedView(view: RouteLocationNormalizedLoaded) {
for (const [i, v] of this.visitedViews.entries()) { for (const [i, v] of this.visitedViews.entries()) {
if (v.path === view.path) { if (v.fullPath === view.fullPath) {
this.visitedViews.splice(i, 1) this.visitedViews.splice(i, 1)
break break
} }
@@ -95,18 +109,18 @@ export const useTagsViewStore = defineStore('tagsView', {
// 删除其他tag // 删除其他tag
delOthersVisitedViews(view: RouteLocationNormalizedLoaded) { delOthersVisitedViews(view: RouteLocationNormalizedLoaded) {
this.visitedViews = this.visitedViews.filter((v) => { this.visitedViews = this.visitedViews.filter((v) => {
return v?.meta?.affix || v.path === view.path return v?.meta?.affix || v.fullPath === view.fullPath
}) })
}, },
// 删除左侧 // 删除左侧
delLeftViews(view: RouteLocationNormalizedLoaded) { delLeftViews(view: RouteLocationNormalizedLoaded) {
const index = findIndex<RouteLocationNormalizedLoaded>( const index = findIndex<RouteLocationNormalizedLoaded>(
this.visitedViews, this.visitedViews,
(v) => v.path === view.path (v) => v.fullPath === view.fullPath
) )
if (index > -1) { if (index > -1) {
this.visitedViews = this.visitedViews.filter((v, i) => { this.visitedViews = this.visitedViews.filter((v, i) => {
return v?.meta?.affix || v.path === view.path || i > index return v?.meta?.affix || v.fullPath === view.fullPath || i > index
}) })
this.addCachedView() this.addCachedView()
} }
@@ -115,18 +129,18 @@ export const useTagsViewStore = defineStore('tagsView', {
delRightViews(view: RouteLocationNormalizedLoaded) { delRightViews(view: RouteLocationNormalizedLoaded) {
const index = findIndex<RouteLocationNormalizedLoaded>( const index = findIndex<RouteLocationNormalizedLoaded>(
this.visitedViews, this.visitedViews,
(v) => v.path === view.path (v) => v.fullPath === view.fullPath
) )
if (index > -1) { if (index > -1) {
this.visitedViews = this.visitedViews.filter((v, i) => { this.visitedViews = this.visitedViews.filter((v, i) => {
return v?.meta?.affix || v.path === view.path || i < index return v?.meta?.affix || v.fullPath === view.fullPath || i < index
}) })
this.addCachedView() this.addCachedView()
} }
}, },
updateVisitedView(view: RouteLocationNormalizedLoaded) { updateVisitedView(view: RouteLocationNormalizedLoaded) {
for (let v of this.visitedViews) { for (let v of this.visitedViews) {
if (v.path === view.path) { if (v.fullPath === view.fullPath) {
v = Object.assign(v, view) v = Object.assign(v, view)
break break
} }

View File

@@ -1,4 +1,4 @@
@import './variables.scss'; @use './variables.scss' as *;
// 导出变量 // 导出变量
:export { :export {
namespace: $namespace; namespace: $namespace;

View File

@@ -1,7 +1,7 @@
@import './var.css'; @use './var.css';
@import './FormCreate/index.scss'; @use './FormCreate/index.scss';
@import './theme.scss'; @use './theme.scss';
@import 'element-plus/theme-chalk/dark/css-vars.css'; @use 'element-plus/theme-chalk/dark/css-vars.css';
.reset-margin [class*='el-icon'] + span { .reset-margin [class*='el-icon'] + span {
margin-left: 2px !important; margin-left: 2px !important;

View File

@@ -10,7 +10,8 @@ const RefreshTokenKey = 'REFRESH_TOKEN'
// 获取token // 获取token
export const getAccessToken = () => { export const getAccessToken = () => {
// 此处与TokenKey相同此写法解决初始化时Cookies中不存在TokenKey报错 // 此处与TokenKey相同此写法解决初始化时Cookies中不存在TokenKey报错
return wsCache.get(AccessTokenKey) ? wsCache.get(AccessTokenKey) : wsCache.get('ACCESS_TOKEN') const accessToken = wsCache.get(AccessTokenKey)
return accessToken ? accessToken : wsCache.get('ACCESS_TOKEN')
} }
// 刷新token // 刷新token

View File

@@ -98,8 +98,9 @@ export const isServer = typeof window === 'undefined'
export const isClient = !isServer export const isClient = !isServer
export const isUrl = (path: string): boolean => { export const isUrl = (path: string): boolean => {
// fix:修复hash路由无法跳转的问题
const reg = const reg =
/(((^https?:(?:\/\/)?)(?:[-:&=\+\$,\w]+@)?[A-Za-z0-9.-]+(?::\d+)?|(?:www.|[-:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&%@.\w_]*)#?(?:[\w]*))?)$/ /(((^https?:(?:\/\/)?)(?:[-:&=\+\$,\w]+@)?[A-Za-z0-9.-]+(?::\d+)?|(?:www.|[-:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%#\/.\w-_]*)?\??(?:[-\+=&%@.\w_]*)#?(?:[\w]*))?)$/
return reg.test(path) return reg.test(path)
} }

View File

@@ -12,8 +12,9 @@ export function checkPermi(value: string[]) {
const { wsCache } = useCache() const { wsCache } = useCache()
const permissionDatas = value const permissionDatas = value
const all_permission = '*:*:*' const all_permission = '*:*:*'
const permissions = wsCache.get(CACHE_KEY.USER).permissions const userInfo = wsCache.get(CACHE_KEY.USER)
const hasPermission = permissions.some((permission) => { const permissions = userInfo?.permissions || []
const hasPermission = permissions.some((permission: string) => {
return all_permission === permission || permissionDatas.includes(permission) return all_permission === permission || permissionDatas.includes(permission)
}) })
return !!hasPermission return !!hasPermission
@@ -32,9 +33,10 @@ export function checkRole(value: string[]) {
if (value && value instanceof Array && value.length > 0) { if (value && value instanceof Array && value.length > 0) {
const { wsCache } = useCache() const { wsCache } = useCache()
const permissionRoles = value const permissionRoles = value
const super_admin = 'admin' const super_admin = 'super_admin'
const roles = wsCache.get(CACHE_KEY.USER).roles const userInfo = wsCache.get(CACHE_KEY.USER)
const hasRole = roles.some((role) => { const roles = userInfo?.roles || []
const hasRole = roles.some((role: string) => {
return super_admin === role || permissionRoles.includes(role) return super_admin === role || permissionRoles.includes(role)
}) })
return !!hasRole return !!hasRole

View File

@@ -3,7 +3,7 @@
<div class="chat-empty"> <div class="chat-empty">
<!-- title --> <!-- title -->
<div class="center-container"> <div class="center-container">
<div class="title">芋道 AI</div> <div class="title">AI对话</div>
<div class="role-list"> <div class="role-list">
<div <div
class="role-item" class="role-item"

View File

@@ -1,14 +1,18 @@
<template> <template>
<ContentWrap> <ContentWrap :body-style="{ padding: '0px' }" class="!mb-0">
<!-- 表单设计器 --> <!-- 表单设计器 -->
<FcDesigner ref="designer" height="780px"> <div
<template #handle> class="h-[calc(100vh-var(--top-tool-height)-var(--tags-view-height)-var(--app-content-padding)-var(--app-content-padding)-2px)]"
<el-button round size="small" type="primary" @click="handleSave"> >
<Icon class="mr-5px" icon="ep:plus" /> <fc-designer class="my-designer" ref="designer" :config="designerConfig">
保存 <template #handle>
</el-button> <el-button size="small" type="success" plain @click="handleSave">
</template> <Icon class="mr-5px" icon="ep:plus" />
</FcDesigner> 保存
</el-button>
</template>
</fc-designer>
</div>
</ContentWrap> </ContentWrap>
<!-- 表单保存的弹窗 --> <!-- 表单保存的弹窗 -->
@@ -55,6 +59,31 @@ const { push, currentRoute } = useRouter() // 路由
const { query } = useRoute() // 路由信息 const { query } = useRoute() // 路由信息
const { delView } = useTagsViewStore() // 视图操作 const { delView } = useTagsViewStore() // 视图操作
// 表单设计器配置
const designerConfig = ref({
switchType: [], // 是否可以切换组件类型,或者可以相互切换的字段
autoActive: true, // 是否自动选中拖入的组件
useTemplate: false, // 是否生成vue2语法的模板组件
formOptions: {}, // 定义表单配置默认值
fieldReadonly: false, // 配置field是否可以编辑
hiddenDragMenu: false, // 隐藏拖拽操作按钮
hiddenDragBtn: false, // 隐藏拖拽按钮
hiddenMenu: [], // 隐藏部分菜单
hiddenItem: [], // 隐藏部分组件
hiddenItemConfig: {}, // 隐藏组件的部分配置项
disabledItemConfig: {}, // 禁用组件的部分配置项
showSaveBtn: false, // 是否显示保存按钮
showConfig: true, // 是否显示右侧的配置界面
showBaseForm: true, // 是否显示组件的基础配置表单
showControl: true, // 是否显示组件联动
showPropsForm: true, // 是否显示组件的属性配置表单
showEventForm: true, // 是否显示组件的事件配置表单
showValidateForm: true, // 是否显示组件的验证配置表单
showFormConfig: true, // 是否显示表单配置
showInputData: true, // 是否显示录入按钮
showDevice: true, // 是否显示多端适配选项
appendConfigData: [] // 定义渲染规则所需的formData
})
const designer = ref() // 表单设计器 const designer = ref() // 表单设计器
useFormCreateDesigner(designer) // 表单设计器增强 useFormCreateDesigner(designer) // 表单设计器增强
const dialogVisible = ref(false) // 弹窗是否展示 const dialogVisible = ref(false) // 弹窗是否展示
@@ -119,3 +148,13 @@ onMounted(async () => {
setConfAndFields(designer, data.conf, data.fields) setConfAndFields(designer, data.conf, data.fields)
}) })
</script> </script>
<style>
.my-designer {
._fc-l,
._fc-m,
._fc-r {
border-top: none;
}
}
</style>

View File

@@ -250,10 +250,12 @@ const handleAudit = async (task, pass) => {
if (!elForm) return if (!elForm) return
let valid = await elForm.validate() let valid = await elForm.validate()
if (!valid) return if (!valid) return
// 校验申请表单 // 校验申请表单(可编辑字段)
if (!fApi.value) return //fixme 有bug 永远为true // TODO @jason之前这里是 if (!fApi.value) return针对业务表单的情况下会导致没办法审核可能要看下。我这里改了点看看是不是还有别的地方兼容性
valid = await fApi.value.validate() if (fApi.value) {
if (!valid) return valid = await fApi.value.validate()
if (!valid) return
}
// 2.1 提交审批 // 2.1 提交审批
const data = { const data = {
@@ -269,7 +271,9 @@ const handleAudit = async (task, pass) => {
data.variables = approveForms.value[index].value data.variables = approveForms.value[index].value
} }
// 获取表单可编辑字段的值 // 获取表单可编辑字段的值
data.variables = getWritableValueOfForm(task.fieldsPermission) if (fApi.value) {
data.variables = getWritableValueOfForm(task.fieldsPermission)
}
await TaskApi.approveTask(data) await TaskApi.approveTask(data)
message.success('审批通过成功') message.success('审批通过成功')

View File

@@ -79,6 +79,10 @@
class="!w-240px" class="!w-240px"
/> />
</el-form-item> </el-form-item>
<el-form-item>
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
</el-form-item>
</el-form> </el-form>
</ContentWrap> </ContentWrap>

View File

@@ -1,16 +1,17 @@
<template> <template>
<ContentWrap> <ContentWrap :body-style="{ padding: '0px' }" class="!mb-0">
<el-row>
<el-col>
<div class="float-right mb-2">
<el-button size="small" type="primary" @click="showJson">生成 JSON</el-button>
<el-button size="small" type="success" @click="showOption">生成 Options</el-button>
<el-button size="small" type="danger" @click="showTemplate">生成组件</el-button>
</div>
</el-col>
</el-row>
<!-- 表单设计器 --> <!-- 表单设计器 -->
<FcDesigner ref="designer" height="780px" /> <div
class="h-[calc(100vh-var(--top-tool-height)-var(--tags-view-height)-var(--app-content-padding)-var(--app-content-padding)-2px)]"
>
<fc-designer class="my-designer" ref="designer" :config="designerConfig">
<template #handle>
<el-button size="small" type="primary" plain @click="showJson">生成JSON</el-button>
<el-button size="small" type="success" plain @click="showOption">生成Options</el-button>
<el-button size="small" type="danger" plain @click="showTemplate">生成组件</el-button>
</template>
</fc-designer>
</div>
</ContentWrap> </ContentWrap>
<!-- 弹窗表单预览 --> <!-- 弹窗表单预览 -->
@@ -43,6 +44,31 @@ defineOptions({ name: 'InfraBuild' })
const { t } = useI18n() // 国际化 const { t } = useI18n() // 国际化
const message = useMessage() // 消息 const message = useMessage() // 消息
// 表单设计器配置
const designerConfig = ref({
switchType: [], // 是否可以切换组件类型,或者可以相互切换的字段
autoActive: true, // 是否自动选中拖入的组件
useTemplate: false, // 是否生成vue2语法的模板组件
formOptions: {}, // 定义表单配置默认值
fieldReadonly: false, // 配置field是否可以编辑
hiddenDragMenu: false, // 隐藏拖拽操作按钮
hiddenDragBtn: false, // 隐藏拖拽按钮
hiddenMenu: [], // 隐藏部分菜单
hiddenItem: [], // 隐藏部分组件
hiddenItemConfig: {}, // 隐藏组件的部分配置项
disabledItemConfig: {}, // 禁用组件的部分配置项
showSaveBtn: false, // 是否显示保存按钮
showConfig: true, // 是否显示右侧的配置界面
showBaseForm: true, // 是否显示组件的基础配置表单
showControl: true, // 是否显示组件联动
showPropsForm: true, // 是否显示组件的属性配置表单
showEventForm: true, // 是否显示组件的事件配置表单
showValidateForm: true, // 是否显示组件的验证配置表单
showFormConfig: true, // 是否显示表单配置
showInputData: true, // 是否显示录入按钮
showDevice: true, // 是否显示多端适配选项
appendConfigData: [] // 定义渲染规则所需的formData
})
const designer = ref() // 表单设计器 const designer = ref() // 表单设计器
const dialogVisible = ref(false) // 弹窗的是否展示 const dialogVisible = ref(false) // 弹窗的是否展示
const dialogTitle = ref('') // 弹窗的标题 const dialogTitle = ref('') // 弹窗的标题
@@ -140,3 +166,13 @@ onMounted(async () => {
hljs.registerLanguage('json', json) hljs.registerLanguage('json', json)
}) })
</script> </script>
<style>
.my-designer {
._fc-l,
._fc-m,
._fc-r {
border-top: none;
}
}
</style>

View File

@@ -80,6 +80,7 @@
<!-- 列表 --> <!-- 列表 -->
<ContentWrap> <ContentWrap>
<el-table v-loading="loading" :data="list" :show-overflow-tooltip="true" :stripe="true"> <el-table v-loading="loading" :data="list" :show-overflow-tooltip="true" :stripe="true">
<el-table-column align="center" label="ID" min-width="180" prop="id" />
<el-table-column align="center" label="封面" min-width="80" prop="picUrl"> <el-table-column align="center" label="封面" min-width="80" prop="picUrl">
<template #default="{ row }"> <template #default="{ row }">
<el-image :src="row.picUrl" class="h-30px w-30px" @click="imagePreview(row.picUrl)" /> <el-image :src="row.picUrl" class="h-30px w-30px" @click="imagePreview(row.picUrl)" />

View File

@@ -121,7 +121,7 @@
label="创建时间" label="创建时间"
align="center" align="center"
prop="createTime" prop="createTime"
width="180" width="170"
:formatter="dateFormatter" :formatter="dateFormatter"
/> />
<el-table-column label="支付金额" align="center" prop="payPrice" width="100"> <el-table-column label="支付金额" align="center" prop="payPrice" width="100">
@@ -157,7 +157,7 @@
</p> </p>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="退款状态" align="center" prop="status"> <el-table-column label="退款状态" align="center" prop="status" width="100">
<template #default="scope"> <template #default="scope">
<dict-tag :type="DICT_TYPE.PAY_REFUND_STATUS" :value="scope.row.status" /> <dict-tag :type="DICT_TYPE.PAY_REFUND_STATUS" :value="scope.row.status" />
</template> </template>

3
types/router.d.ts vendored
View File

@@ -15,6 +15,8 @@ import { defineComponent } from 'vue'
title: 'title' 设置该路由在侧边栏和面包屑中展示的名字 title: 'title' 设置该路由在侧边栏和面包屑中展示的名字
titleSuffix: '2' 当 path 和 title 重复时的后缀或备注
icon: 'svg-name' 设置该路由的图标 icon: 'svg-name' 设置该路由的图标
noCache: true 如果设置为true则不会被 <keep-alive> 缓存(默认 false) noCache: true 如果设置为true则不会被 <keep-alive> 缓存(默认 false)
@@ -37,6 +39,7 @@ declare module 'vue-router' {
hidden?: boolean hidden?: boolean
alwaysShow?: boolean alwaysShow?: boolean
title?: string title?: string
titleSuffix?: string
icon?: string icon?: string
noCache?: boolean noCache?: boolean
breadcrumb?: boolean breadcrumb?: boolean

View File

@@ -43,7 +43,7 @@ export default ({command, mode}: ConfigEnv): UserConfig => {
css: { css: {
preprocessorOptions: { preprocessorOptions: {
scss: { scss: {
additionalData: '@import "./src/styles/variables.scss";', additionalData: '@use "@/styles/variables.scss" as *;',
javascriptEnabled: true javascriptEnabled: true
} }
} }

19
web-types.json Normal file
View File

@@ -0,0 +1,19 @@
{
"$schema": "https://json.schemastore.org/web-types",
"framework": "vue",
"name": "name written in package.json",
"version": "version written in package.json",
"contributions": {
"html": {
"types-syntax": "typescript",
"attributes": [
{
"name": "v-hasPermi"
},
{
"name": "v-hasRole"
}
]
}
}
}