mirror of
https://github.com/mfish-qf/mfish-nocode-view.git
synced 2026-10-30 18:22:35 +08:00
feat: 菜单增加分类
feat: 字典增加icon feat: 样式优化 feat: 启动端口调整
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
# port
|
||||
VITE_PORT = 5281
|
||||
VITE_PORT = 5186
|
||||
|
||||
# title
|
||||
VITE_GLOB_APP_TITLE = 摸鱼低代码平台
|
||||
|
||||
+1
-1
@@ -27,4 +27,4 @@ VITE_GLOB_OAUTH2_URL = http://localhost:8888/oauth2/authorize
|
||||
# VITE_GLOB_OAUTH2_URL = http://app.mfish.com.cn:11116/oauth2/authorize
|
||||
|
||||
# oauth2回调地址
|
||||
VITE_GLOB_OAUTH2_REDIRECT_URI = http://localhost:5281/oauth2
|
||||
VITE_GLOB_OAUTH2_REDIRECT_URI = http://localhost:5186/oauth2
|
||||
|
||||
+1
-1
@@ -12,5 +12,5 @@ RUN npm run build
|
||||
FROM nginx:stable-alpine as production-stage
|
||||
COPY --from=build-stage /app/mfish-nocode-view /usr/share/nginx/html/mfish-nocode-view
|
||||
COPY --from=build-stage /app/config/mfish-nocode-view.conf /etc/nginx/conf.d/mfish-nocode-view.conf
|
||||
EXPOSE 5281
|
||||
EXPOSE 5186
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
|
||||
@@ -99,7 +99,7 @@ pnpm run build
|
||||
|
||||
- 访问前台
|
||||
|
||||
http://localhost:5281
|
||||
http://localhost:5186
|
||||
|
||||
## 功能模块
|
||||
|
||||
|
||||
+1
-1
@@ -3,5 +3,5 @@ services:
|
||||
container_name: mfish-nocode-view
|
||||
image: mfish-nocode-view
|
||||
ports:
|
||||
- 11119:5281
|
||||
- 11119:5186
|
||||
restart: always
|
||||
|
||||
@@ -25,26 +25,26 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"eslint-config-turbo": "^2.2.3",
|
||||
"eslint-config-turbo": "^2.3.0",
|
||||
"eslint-plugin-command": "^0.2.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.13.0",
|
||||
"@eslint/js": "^9.14.0",
|
||||
"@types/eslint": "^9.6.1",
|
||||
"@typescript-eslint/eslint-plugin": "^8.11.0",
|
||||
"@typescript-eslint/parser": "^8.11.0",
|
||||
"eslint": "^9.13.0",
|
||||
"@typescript-eslint/eslint-plugin": "^8.14.0",
|
||||
"@typescript-eslint/parser": "^8.14.0",
|
||||
"eslint": "^9.14.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-eslint-comments": "^3.2.0",
|
||||
"eslint-plugin-jsdoc": "^50.4.3",
|
||||
"eslint-plugin-jsonc": "^2.16.0",
|
||||
"eslint-plugin-jsdoc": "^50.5.0",
|
||||
"eslint-plugin-jsonc": "^2.18.1",
|
||||
"eslint-plugin-no-only-tests": "^3.3.0",
|
||||
"eslint-plugin-prettier": "^5.2.1",
|
||||
"eslint-plugin-regexp": "^2.6.0",
|
||||
"eslint-plugin-regexp": "^2.7.0",
|
||||
"eslint-plugin-unicorn": "^55.0.0",
|
||||
"eslint-plugin-unused-imports": "^4.1.4",
|
||||
"eslint-plugin-vue": "^9.30.0",
|
||||
"globals": "^15.11.0",
|
||||
"eslint-plugin-vue": "^9.31.0",
|
||||
"globals": "^15.12.0",
|
||||
"jsonc-eslint-parser": "^2.4.0",
|
||||
"vue-eslint-parser": "^9.4.3"
|
||||
}
|
||||
|
||||
@@ -23,10 +23,10 @@
|
||||
"dependencies": {
|
||||
"@stylistic/stylelint-plugin": "^3.1.1",
|
||||
"stylelint-config-recess-order": "^5.1.1",
|
||||
"stylelint-scss": "^6.8.1"
|
||||
"stylelint-scss": "^6.9.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"postcss": "^8.4.47",
|
||||
"postcss": "^8.4.49",
|
||||
"postcss-html": "^1.7.0",
|
||||
"postcss-scss": "^4.0.9",
|
||||
"prettier": "^3.3.3",
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
"web.json"
|
||||
],
|
||||
"dependencies": {
|
||||
"@types/node": "^22.8.1",
|
||||
"vite": "^5.4.10"
|
||||
"@types/node": "^22.9.0",
|
||||
"vite": "^5.4.11"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,20 +26,20 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@ant-design/colors": "^7.1.0",
|
||||
"vite": "^5.4.10"
|
||||
"vite": "^5.4.11"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/fs-extra": "^11.0.4",
|
||||
"@vitejs/plugin-vue": "^5.1.4",
|
||||
"@vitejs/plugin-vue-jsx": "^4.0.1",
|
||||
"ant-design-vue": "^4.2.5",
|
||||
"@vitejs/plugin-vue": "^5.2.0",
|
||||
"@vitejs/plugin-vue-jsx": "^4.1.0",
|
||||
"ant-design-vue": "^4.2.6",
|
||||
"dayjs": "^1.11.13",
|
||||
"dotenv": "^16.4.5",
|
||||
"fs-extra": "^11.2.0",
|
||||
"less": "^4.2.0",
|
||||
"picocolors": "^1.1.1",
|
||||
"pkg-types": "^1.2.1",
|
||||
"postcss": "^8.4.47",
|
||||
"postcss": "^8.4.49",
|
||||
"rollup-plugin-visualizer": "^5.12.0",
|
||||
"unbuild": "^2.0.0",
|
||||
"unocss": "^0.61.9",
|
||||
|
||||
+18
-18
@@ -25,7 +25,6 @@
|
||||
"lint:prettier": "prettier --write \"src/**/*.{js,json,tsx,css,less,scss,vue,html,md}\"",
|
||||
"lint:stylelint": "stylelint --cache --fix \"**/*.{vue,less,postcss,css,scss}\" --cache --cache-location node_modules/.cache/stylelint/",
|
||||
"lint:lint-staged": "lint-staged",
|
||||
"gen:icon": "esno ./build/generate/icon/index.ts",
|
||||
"preinstall": "npx only-allow pnpm"
|
||||
},
|
||||
"dependencies": {
|
||||
@@ -36,7 +35,8 @@
|
||||
"@vueuse/core": "^10.11.1",
|
||||
"@vueuse/shared": "^10.11.1",
|
||||
"@zxcvbn-ts/core": "^3.0.4",
|
||||
"ant-design-vue": "^4.2.5",
|
||||
"animate.css": "^4.1.1",
|
||||
"ant-design-vue": "^4.2.6",
|
||||
"axios": "^1.7.7",
|
||||
"bootstrap": "^5.3.3",
|
||||
"codemirror": "5.65.16",
|
||||
@@ -46,8 +46,8 @@
|
||||
"echarts": "^5.5.1",
|
||||
"lodash-es": "^4.17.21",
|
||||
"nprogress": "^0.2.0",
|
||||
"path-to-regexp": "^7.2.0",
|
||||
"pinia": "^2.2.4",
|
||||
"path-to-regexp": "^8.2.0",
|
||||
"pinia": "^2.2.6",
|
||||
"qrcode": "^1.5.4",
|
||||
"qs": "^6.13.0",
|
||||
"resize-observer-polyfill": "^1.5.1",
|
||||
@@ -63,7 +63,7 @@
|
||||
"vuedraggable": "^4.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@iconify/json": "^2.2.265",
|
||||
"@iconify/json": "^2.2.272",
|
||||
"@logicflow/core": "^1.2.28",
|
||||
"@logicflow/extension": "^1.2.28",
|
||||
"@mfish/eslint-config": "workspace:*",
|
||||
@@ -80,25 +80,25 @@
|
||||
"@types/intro.js": "^5.1.5",
|
||||
"@types/jsdom": "^21.1.7",
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"@types/node": "^22.8.1",
|
||||
"@types/node": "^22.9.0",
|
||||
"@types/qrcode": "^1.5.5",
|
||||
"@types/sm-crypto": "^0.3.4",
|
||||
"@types/sortablejs": "^1.15.8",
|
||||
"@typescript-eslint/eslint-plugin": "^8.11.0",
|
||||
"@typescript-eslint/parser": "^8.11.0",
|
||||
"@typescript-eslint/eslint-plugin": "^8.14.0",
|
||||
"@typescript-eslint/parser": "^8.14.0",
|
||||
"@vitejs/plugin-legacy": "^5.4.3",
|
||||
"@vitejs/plugin-vue": "^5.1.4",
|
||||
"@vitejs/plugin-vue-jsx": "^4.0.1",
|
||||
"@vitejs/plugin-vue": "^5.2.0",
|
||||
"@vitejs/plugin-vue-jsx": "^4.1.0",
|
||||
"@vue/eslint-config-prettier": "^9.0.0",
|
||||
"@vue/test-utils": "^2.4.6",
|
||||
"@vue/tsconfig": "^0.5.1",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"cross-env": "^7.0.3",
|
||||
"dotenv": "^16.4.5",
|
||||
"eslint": "^9.13.0",
|
||||
"eslint": "^9.14.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-prettier": "^5.2.1",
|
||||
"eslint-plugin-vue": "^9.30.0",
|
||||
"eslint-plugin-vue": "^9.31.0",
|
||||
"esno": "^4.8.0",
|
||||
"fs-extra": "^11.2.0",
|
||||
"inquirer": "^10.2.2",
|
||||
@@ -107,20 +107,20 @@
|
||||
"naive-ui": "^2.40.1",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"picocolors": "^1.1.1",
|
||||
"postcss": "^8.4.47",
|
||||
"postcss": "^8.4.49",
|
||||
"prettier": "^3.3.3",
|
||||
"prettier-plugin-packagejson": "^2.5.3",
|
||||
"rimraf": "^6.0.1",
|
||||
"rollup": "^4.24.2",
|
||||
"rollup": "^4.27.0",
|
||||
"rollup-plugin-visualizer": "^5.12.0",
|
||||
"stylelint": "^16.10.0",
|
||||
"stylelint-config-standard": "^36.0.1",
|
||||
"stylelint-order": "^6.0.4",
|
||||
"terser": "^5.36.0",
|
||||
"turbo": "^2.2.3",
|
||||
"turbo": "^2.3.0",
|
||||
"typescript": "^5.6.3",
|
||||
"unbuild": "^2.0.0",
|
||||
"vite": "^5.4.10",
|
||||
"vite": "^5.4.11",
|
||||
"vite-plugin-html": "^3.2.2",
|
||||
"vite-plugin-imagemin": "^0.6.1",
|
||||
"vite-plugin-mkcert": "^1.17.6",
|
||||
@@ -128,7 +128,7 @@
|
||||
"vite-plugin-svg-icons": "^2.0.1",
|
||||
"vite-plugin-vue-setup-extend": "^0.4.0",
|
||||
"vue-eslint-parser": "^9.4.3",
|
||||
"vue-tsc": "^2.1.8"
|
||||
"vue-tsc": "^2.1.10"
|
||||
},
|
||||
"resolutions": {
|
||||
"bin-wrapper": "npm:bin-wrapper-china",
|
||||
@@ -154,5 +154,5 @@
|
||||
"node": ">=20",
|
||||
"pnpm": ">=9"
|
||||
},
|
||||
"packageManager": "pnpm@9.12.2"
|
||||
"packageManager": "pnpm@9.12.3"
|
||||
}
|
||||
|
||||
Generated
+907
-855
File diff suppressed because it is too large
Load Diff
@@ -12,6 +12,7 @@ export interface DictItem extends BaseEntity<string> {
|
||||
dictValue: string;
|
||||
valueType: number;
|
||||
dictSort: number;
|
||||
icon: string;
|
||||
color: string;
|
||||
status: number;
|
||||
remark: string;
|
||||
|
||||
@@ -24,9 +24,9 @@
|
||||
<template #item="{ index, element }">
|
||||
<div @mouseover="tagMouseOver(index)" @mouseleave="tagMouseLeave" style="position: relative">
|
||||
<div @drop="handleDropItem($event, index)">
|
||||
<slot v-bind="{ index, element } || {}" name="tag" v-if="element.slot"></slot>
|
||||
<slot v-bind="{ index, element }" name="tag" v-if="element.slot"></slot>
|
||||
<ATag v-else class="pointer" :color="blockColor" @click="editBlock(index, element)">
|
||||
<template #icon> <slot v-bind="{ index, element } || {}" name="tagIcon"></slot> </template>
|
||||
<template #icon> <slot v-bind="{ index, element }" name="tagIcon"></slot> </template>
|
||||
{{ element.name }}
|
||||
</ATag>
|
||||
</div>
|
||||
|
||||
@@ -99,10 +99,10 @@
|
||||
};
|
||||
}
|
||||
|
||||
function handlePreview(file) {
|
||||
function handlePreview(file: any) {
|
||||
filePreviewRef.value?.show({ fileKey: file.response.fileKey, fileType: file.type });
|
||||
}
|
||||
function handleRemove(file) {
|
||||
function handleRemove(file: any) {
|
||||
emit("remove", toRaw(unref(file)), getFiles());
|
||||
}
|
||||
function getFiles() {
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<template>
|
||||
<SvgIcon :size="size" :name="getSvgIcon" v-if="isSvgIcon" class="anticon" :class="[$attrs.class]" :spin="spin" />
|
||||
<IconFont v-else-if="isIconFont" :icon="getIconfont" :size="size" :color="color" />
|
||||
<IconFont v-else-if="isIconFont" :icon="getIconfont" :size="getWrapStyle.fontSize" :color="getWrapStyle.color" />
|
||||
<span v-else class="app-iconify anticon" :class="[$attrs.class, spin && 'app-iconify-spin']" :style="getWrapStyle">
|
||||
<Icon :icon="getIconRef" />
|
||||
</span>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { PropType, computed, ComputedRef } from "vue";
|
||||
import { PropType, computed } from "vue";
|
||||
import SvgIcon from "./SvgIcon.vue";
|
||||
import { Icon } from "@iconify/vue";
|
||||
import { isString } from "@/utils/Is";
|
||||
@@ -19,7 +19,7 @@
|
||||
// icon name
|
||||
icon: propTypes.string,
|
||||
// icon color
|
||||
color: [String, Object] as PropType<string | ComputedRef<string>>,
|
||||
color: { type: String },
|
||||
// icon size
|
||||
size: {
|
||||
type: [String, Number] as PropType<string | number>,
|
||||
@@ -43,16 +43,22 @@
|
||||
if (isString(size)) {
|
||||
fs = Number.parseInt(size, 10);
|
||||
}
|
||||
const newColor = { color: "inherit" };
|
||||
if (color) {
|
||||
newColor.color =
|
||||
color === "primary"
|
||||
? defaultSeed.colorPrimary
|
||||
: color === "success"
|
||||
? defaultSeed.colorSuccess
|
||||
: color === "warning"
|
||||
? defaultSeed.colorWarning
|
||||
: color === "error"
|
||||
? defaultSeed.colorError
|
||||
: color;
|
||||
}
|
||||
return {
|
||||
fontSize: `${fs}px`,
|
||||
color:
|
||||
color === "success"
|
||||
? defaultSeed.colorSuccess
|
||||
: color === "warning"
|
||||
? defaultSeed.colorWarning
|
||||
: color === "error"
|
||||
? defaultSeed.colorError
|
||||
: color,
|
||||
...newColor,
|
||||
display: "inline-flex"
|
||||
};
|
||||
});
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
<template>
|
||||
<AInput
|
||||
disabled
|
||||
<Input
|
||||
:style="{ width }"
|
||||
:placeholder="t('component.icon.placeholder')"
|
||||
:class="prefixCls"
|
||||
v-model:value="currentSelect"
|
||||
@click="triggerPopover"
|
||||
:allow-clear="props.allowClear"
|
||||
:readonly="props.readonly"
|
||||
>
|
||||
<template #addonAfter>
|
||||
<APopover placement="bottomLeft" trigger="click" v-model="visible" :overlay-class-name="`${prefixCls}-popover`">
|
||||
<Popover placement="bottomLeft" trigger="click" v-model="visible" :overlay-class-name="`${prefixCls}-popover`">
|
||||
<template #title>
|
||||
<div class="flex justify-between">
|
||||
<AInput :placeholder="t('component.icon.search')" @change="debounceHandleSearchChange" allow-clear />
|
||||
<Input :placeholder="t('component.icon.search')" @change="debounceHandleSearchChange" allow-clear />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -26,14 +28,13 @@
|
||||
@click="handleClick(icon)"
|
||||
:title="icon"
|
||||
>
|
||||
<!-- <Icon :icon="icon" :prefix="prefix" /> -->
|
||||
<SvgIcon v-if="isSvgMode" :name="icon" />
|
||||
<Icon :icon="icon" v-else />
|
||||
</li>
|
||||
</ul>
|
||||
</ScrollContainer>
|
||||
<div class="flex py-2 items-center justify-center" v-if="getTotal >= pageSize">
|
||||
<APagination
|
||||
<Pagination
|
||||
show-less-items
|
||||
size="small"
|
||||
:page-size="pageSize"
|
||||
@@ -43,19 +44,19 @@
|
||||
</div>
|
||||
</div>
|
||||
<template v-else>
|
||||
<div class="p-5">
|
||||
<AEmpty />
|
||||
</div>
|
||||
<div class="p-5"><Empty /> </div>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<span class="cursor-pointer px-2 py-1 flex items-center" v-if="isSvgMode && currentSelect">
|
||||
<SvgIcon :name="currentSelect" />
|
||||
</span>
|
||||
<Icon :icon="currentSelect || 'ion:apps-outline'" class="cursor-pointer px-2 py-1" v-else />
|
||||
</APopover>
|
||||
<div ref="trigger">
|
||||
<span class="cursor-pointer px-2 py-1 flex items-center" v-if="isSvgMode && currentSelect">
|
||||
<SvgIcon :name="currentSelect" />
|
||||
</span>
|
||||
<Icon :icon="currentSelect || 'ion:apps-outline'" class="cursor-pointer px-2 py-1" v-else />
|
||||
</div>
|
||||
</Popover>
|
||||
</template>
|
||||
</AInput>
|
||||
</Input>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, watchEffect, watch, unref } from "vue";
|
||||
@@ -65,42 +66,45 @@
|
||||
import Icon from "./Icon.vue";
|
||||
import SvgIcon from "./SvgIcon.vue";
|
||||
import iconsData from "../data/icons.data";
|
||||
import { propTypes } from "@/utils/PropTypes";
|
||||
import { usePagination } from "@/hooks/web/UsePagination";
|
||||
import { useDebounceFn } from "@vueuse/core";
|
||||
import { useI18n } from "@/hooks/web/UseI18n";
|
||||
import { useCopyToClipboard } from "@/hooks/web/UseCopyToClipboard";
|
||||
import { useMessage } from "@/hooks/web/UseMessage";
|
||||
import svgIcons from "virtual:svg-icons-names";
|
||||
|
||||
const props = defineProps({
|
||||
value: propTypes.string,
|
||||
width: propTypes.string.def("100%"),
|
||||
pageSize: propTypes.number.def(140),
|
||||
copy: propTypes.bool.def(false),
|
||||
mode: propTypes.oneOf<("svg" | "iconify")[]>(["svg", "iconify"]).def("iconify")
|
||||
import { useMessage } from "@/hooks/web/UseMessage";
|
||||
interface Props {
|
||||
value?: string;
|
||||
width?: string;
|
||||
pageSize?: number;
|
||||
copy?: boolean;
|
||||
mode?: "svg" | "iconify";
|
||||
allowClear?: boolean;
|
||||
readonly?: boolean;
|
||||
}
|
||||
// Don't inherit FormItem disabled、placeholder...
|
||||
defineOptions({
|
||||
inheritAttrs: false
|
||||
});
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
value: "",
|
||||
width: "100%",
|
||||
pageSize: 140,
|
||||
copy: false,
|
||||
mode: "iconify",
|
||||
allowClear: true,
|
||||
readonly: false
|
||||
});
|
||||
|
||||
const emit = defineEmits(["change", "update:value"]);
|
||||
// 没有使用别名引入,是因为WebStorm当前版本还不能正确识别,会报unused警告
|
||||
const AInput = Input;
|
||||
const APopover = Popover;
|
||||
const APagination = Pagination;
|
||||
const AEmpty = Empty;
|
||||
|
||||
function getIcons() {
|
||||
const data = iconsData as any;
|
||||
const prefix: string = data?.prefix ?? "";
|
||||
let result: string[] = [];
|
||||
if (prefix) {
|
||||
result = (data?.icons ?? []).map((item) => `${prefix}:${item}`);
|
||||
} else if (Array.isArray(iconsData)) {
|
||||
result = iconsData as string[];
|
||||
}
|
||||
return result;
|
||||
const prefix = iconsData.prefix;
|
||||
return iconsData.icons.map((icon) => `${prefix}:${icon}`);
|
||||
}
|
||||
|
||||
function getSvgIcons() {
|
||||
return svgIcons.map((icon) => icon.replace("icon-", ""));
|
||||
return svgIcons.map((icon: string) => icon.replace("icon-", ""));
|
||||
}
|
||||
|
||||
const isSvgMode = props.mode === "svg";
|
||||
@@ -109,6 +113,13 @@
|
||||
const currentSelect = ref("");
|
||||
const visible = ref(false);
|
||||
const currentList = ref(icons);
|
||||
const trigger = ref<HTMLDivElement>();
|
||||
|
||||
const triggerPopover = () => {
|
||||
if (trigger.value) {
|
||||
trigger.value.click();
|
||||
}
|
||||
};
|
||||
|
||||
const { t } = useI18n();
|
||||
const { prefixCls } = useDesign("icon-picker");
|
||||
@@ -127,10 +138,9 @@
|
||||
() => currentSelect.value,
|
||||
(v) => {
|
||||
emit("update:value", v);
|
||||
return emit("change", v);
|
||||
emit("change", v);
|
||||
}
|
||||
);
|
||||
|
||||
function handlePageChange(page: number) {
|
||||
setCurrentPage(page);
|
||||
}
|
||||
@@ -145,8 +155,9 @@
|
||||
}
|
||||
}
|
||||
|
||||
function handleSearchChange(e: ChangeEvent) {
|
||||
const value = e.target.value;
|
||||
function handleSearchChange(e: Event) {
|
||||
const value = (e.target as HTMLInputElement).value;
|
||||
|
||||
if (!value) {
|
||||
setCurrentPage(1);
|
||||
currentList.value = icons;
|
||||
@@ -163,6 +174,10 @@
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.ant-input {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&-popover {
|
||||
width: 300px;
|
||||
|
||||
|
||||
@@ -46,7 +46,8 @@
|
||||
.modal-icon-info {
|
||||
color: @button-primary-color !important;
|
||||
}
|
||||
.ant-layout-header{
|
||||
|
||||
.ant-layout-header {
|
||||
height: @header-height !important;
|
||||
padding-inline: 0 !important;
|
||||
line-height: @header-height !important;
|
||||
@@ -68,9 +69,21 @@
|
||||
> div {
|
||||
> div {
|
||||
max-width: 100%;
|
||||
> div{
|
||||
|
||||
> div {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ant-segmented-item-selected {
|
||||
.ant-segmented-item-label {
|
||||
color: @main-color;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-segmented-item {
|
||||
margin: 0 2px 0 2px;
|
||||
}
|
||||
|
||||
@@ -107,11 +107,13 @@ html {
|
||||
// ==============screen=========
|
||||
// =================================
|
||||
@screen-item-normal-color: #666;
|
||||
@screen-item-normal-color-light: #999;
|
||||
@screen-input-bg-color-dark: #141414;
|
||||
@screen-item-normal-hover-color: lighten(@screen-item-normal-color, 10%);;
|
||||
@screen-header-color-light: #f0f2f5;
|
||||
@screen-header-color-light: #f0f1f3;
|
||||
@screen-header-color-dark: #232324;
|
||||
@screen-header-color-light-hover: lighten(@screen-header-color-light, 1%);
|
||||
@screen-header-color-dark-hover: lighten(@screen-header-color-dark, 1%);
|
||||
@screen-header-color-light-hover: #f8f8f9;
|
||||
@screen-header-color-dark-hover: #292929;
|
||||
// =================================
|
||||
// ==============button=============
|
||||
// =================================
|
||||
|
||||
@@ -12,7 +12,7 @@ import { useI18n } from "@/hooks/web/UseI18n";
|
||||
import { useLocaleStore } from "@/store/modules/I18n";
|
||||
|
||||
export function useTitle() {
|
||||
const { title } = useGlobSetting();
|
||||
const { shortName } = useGlobSetting();
|
||||
const { currentRoute } = useRouter();
|
||||
const pageTitle = usePageTitle();
|
||||
const { t } = useI18n();
|
||||
@@ -25,7 +25,7 @@ export function useTitle() {
|
||||
return;
|
||||
}
|
||||
const tTitle = t(route?.meta?.title as string);
|
||||
pageTitle.value = tTitle ? `${tTitle}-${title}` : title;
|
||||
pageTitle.value = tTitle ? `${tTitle}-${shortName}` : shortName;
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { App } from "vue";
|
||||
import type { I18n, I18nOptions } from "vue-i18n";
|
||||
import type { I18nOptions } from "vue-i18n";
|
||||
import { createI18n } from "vue-i18n";
|
||||
import { setHtmlPageLang, setLoadLocalePool } from "./Helper";
|
||||
import { localeSetting } from "@/settings/I18nSetting";
|
||||
@@ -39,7 +39,7 @@ async function createI18nOptions(): Promise<I18nOptions> {
|
||||
// setup i18n instance with glob
|
||||
async function setupI18n(app: App) {
|
||||
const options = await createI18nOptions();
|
||||
i18n = createI18n(options) as I18n;
|
||||
i18n = createI18n(options) as ReturnType<typeof createI18n>;
|
||||
app.use(i18n);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@ import "virtual:unocss-devtools";
|
||||
import "@/design/index.less";
|
||||
import "virtual:svg-icons-register";
|
||||
import "ant-design-vue/dist/reset.css";
|
||||
// 引入动画
|
||||
import "animate.css/animate.min.css";
|
||||
import App from "./App.vue";
|
||||
import { createApp } from "vue";
|
||||
import { router, setupRouter } from "./router";
|
||||
|
||||
@@ -16,6 +16,7 @@ export interface AppRouteRecordRaw extends Omit<RouteRecordRaw, "children"> {
|
||||
children?: AppRouteRecordRaw[];
|
||||
props?: Recordable;
|
||||
fullPath?: string;
|
||||
hideChildrenInMenu?: boolean;
|
||||
}
|
||||
|
||||
export interface MenuTag {
|
||||
|
||||
@@ -7,7 +7,7 @@ import { curLoginType, oauth2Config } from "@/settings/LoginSetting";
|
||||
import type { Recordable } from "@mfish/types";
|
||||
|
||||
const ROOT_PATH = RootRoute().path;
|
||||
const whitePathList: PageEnum[] = [PageEnum.BASE_LOGIN, PageEnum.OAUTH_LOGIN, PageEnum.ERROR_LOGIN];
|
||||
const whitePathList: Set<PageEnum> = new Set([PageEnum.BASE_LOGIN, PageEnum.OAUTH_LOGIN, PageEnum.ERROR_LOGIN]);
|
||||
|
||||
export function createPermissionGuard(router: Router) {
|
||||
const userStore = useUserStoreWithOut();
|
||||
@@ -15,7 +15,7 @@ export function createPermissionGuard(router: Router) {
|
||||
router.beforeEach(async (to, from, next) => {
|
||||
const token = userStore.getToken;
|
||||
// 白名单路径允许直接访问
|
||||
if (whitePathList.includes(to.path as PageEnum)) {
|
||||
if (whitePathList.has(to.path as PageEnum)) {
|
||||
// 如果访问登陆页面且token存在,判断token是否有效直接进入redirect地址或首页地址
|
||||
if (to.path === PageEnum.BASE_LOGIN && token) {
|
||||
// 增加try catch方式请求异常造成无法返回首页
|
||||
|
||||
Vendored
+1
@@ -17,6 +17,7 @@ import {
|
||||
import { DEFAULT_CACHE_TIME } from "@/settings/EncryptionSetting";
|
||||
import { toRaw } from "vue";
|
||||
import { pick, omit } from "lodash-es";
|
||||
import { Nullable } from "@mfish/types";
|
||||
|
||||
interface BasicStore {
|
||||
[TOKEN_KEY]: string | number | null | undefined;
|
||||
|
||||
Vendored
+1
@@ -2,6 +2,7 @@ import { cacheCipher } from "@/settings/EncryptionSetting";
|
||||
import type { EncryptionParams } from "@/utils/Cipher";
|
||||
import { AesEncryption } from "@/utils/Cipher";
|
||||
import { isNullOrUnDef } from "@/utils/Is";
|
||||
import { Nullable } from "@mfish/types";
|
||||
|
||||
export interface CreateStorageParams extends EncryptionParams {
|
||||
prefixKey: string;
|
||||
|
||||
@@ -6,7 +6,9 @@
|
||||
<template>
|
||||
<div :class="`${prefixCls}`">
|
||||
<div class="header">
|
||||
<div class="title">{{ `数据表:${curNode?.tableName?.toUpperCase()}` }}</div>
|
||||
<div class="title">
|
||||
{{ `数据表:${curNode?.tableName?.toUpperCase() ? curNode.tableName.toUpperCase() : "无"}` }}
|
||||
</div>
|
||||
<div><slot name="button" v-bind="{ data: curNode }"></slot></div>
|
||||
</div>
|
||||
<ATabs default-active-key="1" @change="changeTab">
|
||||
@@ -90,6 +92,7 @@
|
||||
}
|
||||
|
||||
async function buildTableData(page?: any) {
|
||||
if (!condition.value.connectId) return;
|
||||
await nextTick();
|
||||
tableLoading(true);
|
||||
let pageNum = 1;
|
||||
|
||||
@@ -2,6 +2,7 @@ import { BasicColumn } from "@/components/general/Table";
|
||||
import { FormSchema } from "@/components/general/Table";
|
||||
import { h } from "vue";
|
||||
import { Tag } from "ant-design-vue";
|
||||
import { Icon } from "@/components/general/Icon";
|
||||
|
||||
/**
|
||||
* @description: 字典项
|
||||
@@ -37,6 +38,14 @@ export const columns: BasicColumn[] = [
|
||||
return color;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "图标",
|
||||
dataIndex: "icon",
|
||||
width: 50,
|
||||
customRender: ({ record }) => {
|
||||
return h(Icon, { icon: record.icon, color: record.color });
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "值类型",
|
||||
dataIndex: "valueType",
|
||||
@@ -160,6 +169,11 @@ export const dictItemFormSchema: FormSchema[] = [
|
||||
label: "字典颜色",
|
||||
component: "Input"
|
||||
},
|
||||
{
|
||||
field: "icon",
|
||||
label: "图标",
|
||||
component: "IconPicker"
|
||||
},
|
||||
{
|
||||
field: "remark",
|
||||
label: "备注",
|
||||
|
||||
@@ -14,6 +14,15 @@ export const columns: BasicColumn[] = [
|
||||
width: 200,
|
||||
align: "left"
|
||||
},
|
||||
{
|
||||
dataIndex: "menuType",
|
||||
title: "菜单类型",
|
||||
width: 80,
|
||||
customRender: ({ value }) =>
|
||||
h(Tag, value === 0 ? { color: "green" } : value === 1 ? { color: "blue" } : {}, () =>
|
||||
value === 0 ? "目录" : value === 1 ? "菜单" : value === 2 ? "按钮" : "未知"
|
||||
)
|
||||
},
|
||||
{
|
||||
title: "菜单状态",
|
||||
dataIndex: "isVisible",
|
||||
@@ -227,8 +236,10 @@ export class MenuDesc {
|
||||
{
|
||||
field: "menuType",
|
||||
label: "菜单类型",
|
||||
render: (val) =>
|
||||
h(Tag, { color: "green" }, () => (val === 0 ? "目录" : val === 1 ? "菜单" : val === 2 ? "按钮" : "未知"))
|
||||
render: (value) =>
|
||||
h(Tag, value === 0 ? { color: "green" } : value === 1 ? { color: "blue" } : {}, () =>
|
||||
value === 0 ? "目录" : value === 1 ? "菜单" : value === 2 ? "按钮" : "未知"
|
||||
)
|
||||
},
|
||||
{
|
||||
field: "menuName",
|
||||
@@ -257,7 +268,7 @@ export class MenuDesc {
|
||||
field: "menuIcon",
|
||||
label: "图标",
|
||||
show: (values) => {
|
||||
if (!values) return;
|
||||
if (!values) return false;
|
||||
return !isButton(values.menuType);
|
||||
}
|
||||
},
|
||||
@@ -265,7 +276,7 @@ export class MenuDesc {
|
||||
field: "routePath",
|
||||
label: "路由地址",
|
||||
show: (values) => {
|
||||
if (!values) return;
|
||||
if (!values) return false;
|
||||
return !isButton(values.menuType);
|
||||
}
|
||||
},
|
||||
@@ -273,7 +284,7 @@ export class MenuDesc {
|
||||
field: "component",
|
||||
label: "组件路径",
|
||||
show: (values) => {
|
||||
if (!values) return;
|
||||
if (!values) return false;
|
||||
return isMenu(values.menuType);
|
||||
}
|
||||
},
|
||||
@@ -281,7 +292,7 @@ export class MenuDesc {
|
||||
field: "permissions",
|
||||
label: "权限标识",
|
||||
show: (values) => {
|
||||
if (!values) return;
|
||||
if (!values) return false;
|
||||
return isButton(values.menuType);
|
||||
}
|
||||
},
|
||||
@@ -289,7 +300,7 @@ export class MenuDesc {
|
||||
field: "isVisible",
|
||||
label: "菜单状态",
|
||||
show: (values) => {
|
||||
if (!values) return;
|
||||
if (!values) return false;
|
||||
return !isButton(values.menuType);
|
||||
},
|
||||
render: (val) => YNTag_Name(val, "显示", "隐藏")
|
||||
@@ -298,7 +309,7 @@ export class MenuDesc {
|
||||
field: "activeMenu",
|
||||
label: "激活菜单",
|
||||
show: (values) => {
|
||||
if (!values) return;
|
||||
if (!values) return false;
|
||||
return isMenu(values.menuType) && values.isVisible === 0;
|
||||
}
|
||||
},
|
||||
@@ -306,7 +317,7 @@ export class MenuDesc {
|
||||
field: "isExternal",
|
||||
label: "新窗口打开",
|
||||
show: (values) => {
|
||||
if (!values) return;
|
||||
if (!values) return false;
|
||||
return isMenu(values.menuType);
|
||||
},
|
||||
render: (val) => YNTag(val)
|
||||
@@ -315,7 +326,7 @@ export class MenuDesc {
|
||||
field: "isKeepalive",
|
||||
label: "是否缓存",
|
||||
show: (values) => {
|
||||
if (!values) return;
|
||||
if (!values) return false;
|
||||
return isMenu(values.menuType);
|
||||
},
|
||||
render: (val) => YNTag(val)
|
||||
|
||||
Reference in New Issue
Block a user