!36 use unocss
* chore: update deps * fix: dark * fix: use table * feat: 解决Form组件slot必须传递component字段才显示的问题 * style(TableColumn): fix Column settings container is too wide * fix: eslint * chore: update deps * refactor: use setup * docs: doc * refactor: use unocsspull/38/head
parent
6b8325c4af
commit
2334fc31ab
|
@ -6,6 +6,7 @@
|
|||
"stylelint.vscode-stylelint",
|
||||
"dbaeumer.vscode-eslint",
|
||||
"esbenp.prettier-vscode",
|
||||
"usernamehw.errorlens",
|
||||
"mrmlnc.vscode-less",
|
||||
"lokalise.i18n-ally",
|
||||
"redhat.vscode-yaml",
|
||||
|
|
|
@ -66,6 +66,12 @@
|
|||
"source.fixAll.eslint": true,
|
||||
"source.organizeImports": false
|
||||
},
|
||||
"eslint.rules.customizations": [
|
||||
{
|
||||
"rule": "@stylistic/*",
|
||||
"severity": "off"
|
||||
}
|
||||
],
|
||||
"eslint.validate": [
|
||||
"javascript",
|
||||
"javascriptreact",
|
||||
|
@ -82,7 +88,7 @@
|
|||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[typescript]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
"editor.defaultFormatter": "rvest.vs-code-prettier-eslint"
|
||||
},
|
||||
"[typescriptreact]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
|
@ -120,6 +126,7 @@
|
|||
"i18n-ally.enabledFrameworks": ["vue", "react"],
|
||||
"cSpell.words": [
|
||||
"antd",
|
||||
"antdv",
|
||||
"antfu",
|
||||
"antv",
|
||||
"brotli",
|
||||
|
@ -166,6 +173,9 @@
|
|||
"*.env": "$(capture).env.*",
|
||||
"package.json": ".hintrc,pnpm-lock.yaml,yarn.lock,LICENSE,README*,CHANGELOG*,CNAME,.gitattributes,.gitignore,prettier.config.js,stylelint.config.js,commitlint.config.js,.stylelintignore,.prettierignore,.gitpod.yml,.eslintrc.js,.eslintignore"
|
||||
},
|
||||
"eslint.codeAction.showDocumentation": {
|
||||
"enable": true
|
||||
},
|
||||
"terminal.integrated.scrollback": 10000,
|
||||
"nuxt.isNuxtApp": false
|
||||
}
|
||||
|
|
|
@ -35,8 +35,8 @@
|
|||
| [pinia](https://pinia.vuejs.org/) | Vue 存储库 替代 vuex5 | 2.1.6 |
|
||||
| [vueuse](https://vueuse.org/) | 常用工具集 | 10.4.1 |
|
||||
| [vue-i18n](https://kazupon.github.io/vue-i18n/zh/introduction.html/) | 国际化 | 9.4.1 |
|
||||
| [vue-router](https://router.vuejs.org/) | Vue 路由 | 4.2.4 |
|
||||
| [unocss](https://uno.antfu.me/) | 原子 css | 0.55.7 |
|
||||
| [vue-router](https://router.vuejs.org/) | Vue 路由 | 4.2.5 |
|
||||
| [unocss](https://uno.antfu.me/) | 原子 css | 0.56.1 |
|
||||
| [iconify](https://icon-sets.iconify.design/) | 在线图标库 | 3.1.1 |
|
||||
|
||||
- ![alt VbenAdmin](https://anncwb.github.io/anncwb/images/preview1.png)
|
||||
|
|
18
package.json
18
package.json
|
@ -76,7 +76,7 @@
|
|||
"vue": "^3.3.4",
|
||||
"vue-i18n": "^9.4.1",
|
||||
"vue-json-pretty": "^2.2.4",
|
||||
"vue-router": "^4.2.4",
|
||||
"vue-router": "^4.2.5",
|
||||
"vue-types": "^5.1.1",
|
||||
"vuedraggable": "^4.1.0",
|
||||
"xlsx": "^0.18.5"
|
||||
|
@ -84,7 +84,7 @@
|
|||
"devDependencies": {
|
||||
"@commitlint/cli": "^17.7.1",
|
||||
"@commitlint/config-conventional": "^17.7.0",
|
||||
"@iconify/json": "^2.2.117",
|
||||
"@iconify/json": "^2.2.119",
|
||||
"@purge-icons/generated": "^0.9.0",
|
||||
"@types/codemirror": "^5.60.10",
|
||||
"@types/crypto-js": "^4.1.2",
|
||||
|
@ -92,10 +92,10 @@
|
|||
"@types/inquirer": "^9.0.3",
|
||||
"@types/lodash-es": "^4.17.9",
|
||||
"@types/node": "^20.6.0",
|
||||
"@types/nprogress": "^0.2.0",
|
||||
"@types/nprogress": "^0.2.1",
|
||||
"@types/qs": "^6.9.8",
|
||||
"@types/sortablejs": "^1.15.2",
|
||||
"@unocss/eslint-config": "^0.56.0",
|
||||
"@unocss/eslint-config": "^0.56.1",
|
||||
"@vitejs/plugin-vue": "4.3.4",
|
||||
"@vitejs/plugin-vue-jsx": "^3.0.2",
|
||||
"@vue/compiler-sfc": "^3.3.4",
|
||||
|
@ -104,7 +104,7 @@
|
|||
"cz-git": "^1.7.1",
|
||||
"czg": "^1.7.1",
|
||||
"dotenv": "^16.3.1",
|
||||
"eslint": "^8.49.0",
|
||||
"eslint": "^8.50.0",
|
||||
"esno": "^0.17.0",
|
||||
"fs-extra": "^11.1.1",
|
||||
"husky": "^8.0.3",
|
||||
|
@ -117,7 +117,7 @@
|
|||
"postcss-less": "^6.0.0",
|
||||
"prettier": "^3.0.3",
|
||||
"rimraf": "^5.0.1",
|
||||
"rollup": "^3.29.2",
|
||||
"rollup": "^3.29.3",
|
||||
"rollup-plugin-visualizer": "^5.9.2",
|
||||
"stylelint": "^15.10.3",
|
||||
"stylelint-config-recess-order": "^4.3.0",
|
||||
|
@ -126,9 +126,9 @@
|
|||
"stylelint-config-standard": "^34.0.0",
|
||||
"stylelint-order": "^6.0.3",
|
||||
"stylelint-prettier": "^4.0.2",
|
||||
"terser": "^5.19.4",
|
||||
"terser": "^5.20.0",
|
||||
"typescript": "^5.2.2",
|
||||
"unocss": "^0.56.0",
|
||||
"unocss": "^0.56.1",
|
||||
"vite": "^4.4.9",
|
||||
"vite-plugin-compression": "^0.5.1",
|
||||
"vite-plugin-mkcert": "^1.16.0",
|
||||
|
@ -138,7 +138,7 @@
|
|||
"vite-plugin-svg-icons": "^2.0.1",
|
||||
"vite-vue-plugin-html": "^1.0.2",
|
||||
"vue-eslint-parser": "^9.3.1",
|
||||
"vue-tsc": "^1.8.11"
|
||||
"vue-tsc": "^1.8.13"
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.{js,jsx,ts,tsx}": [
|
||||
|
|
1712
pnpm-lock.yaml
1712
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
|
@ -8,7 +8,7 @@ const { t } = useI18n()
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div :class="`${prefixCls}`">
|
||||
<div class="relative h-10 flex flex-shrink-0 items-center border-t-1 rounded-bl-2xl px-4 py-0 dark:border-light-100">
|
||||
<AppSearchKeyItem :class="`${prefixCls}-item`" icon="ant-design:enter-outlined" />
|
||||
<span>{{ t('component.app.toSearch') }}</span>
|
||||
<AppSearchKeyItem :class="`${prefixCls}-item`" icon="ion:arrow-up-outline" />
|
||||
|
@ -23,18 +23,6 @@ const { t } = useI18n()
|
|||
@prefix-cls: ~'@{namespace}-app-search-footer';
|
||||
|
||||
.@{prefix-cls} {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
align-items: center;
|
||||
height: 44px;
|
||||
padding: 0 16px;
|
||||
font-size: 12px;
|
||||
// color: var(--text-color);
|
||||
// background-color: var(--component-background);
|
||||
border-top: 1px solid var(--border-color);
|
||||
border-radius: 0 0 16px 16px;
|
||||
|
||||
&-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
|
|
@ -6,7 +6,6 @@ import { InfoCircleOutlined } from '@ant-design/icons-vue'
|
|||
import { getPopupContainer } from '@/utils'
|
||||
import { isArray, isString } from '@/utils/is'
|
||||
import { getSlot } from '@/utils/helper/tsxHelper'
|
||||
import { useDesign } from '@/hooks/web/useDesign'
|
||||
|
||||
const props = {
|
||||
/**
|
||||
|
@ -44,7 +43,6 @@ export default defineComponent({
|
|||
components: { Tooltip },
|
||||
props,
|
||||
setup(props, { slots }) {
|
||||
const { prefixCls } = useDesign('basic-help')
|
||||
|
||||
const getTooltipStyle = computed((): CSSProperties => ({ color: props.color, fontSize: props.fontSize }))
|
||||
|
||||
|
@ -74,14 +72,14 @@ export default defineComponent({
|
|||
return () => {
|
||||
return (
|
||||
<Tooltip
|
||||
overlayClassName={`${prefixCls}__wrap`}
|
||||
overlayClassName="overlay-class"
|
||||
title={<div style={unref(getTooltipStyle)}>{renderTitle()}</div>}
|
||||
autoAdjustOverflow={true}
|
||||
overlayStyle={unref(getOverlayStyle)}
|
||||
placement={props.placement as 'right'}
|
||||
getPopupContainer={() => getPopupContainer()}
|
||||
>
|
||||
<span class={prefixCls}>{getSlot(slots) || <InfoCircleOutlined />}</span>
|
||||
<span class="ml-1.5 inline-block cursor-pointer text-sm">{getSlot(slots) || <InfoCircleOutlined />}</span>
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
|
@ -89,19 +87,10 @@ export default defineComponent({
|
|||
})
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@prefix-cls: ~'@{namespace}-basic-help';
|
||||
|
||||
.@{prefix-cls} {
|
||||
display: inline-block;
|
||||
margin-left: 6px;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
|
||||
&__wrap {
|
||||
p {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
<style>
|
||||
.overlay-class {
|
||||
p {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -31,7 +31,7 @@ const props = {
|
|||
const ItemContent: FunctionalComponent<ItemContentProps> = (props) => {
|
||||
const { item } = props
|
||||
return (
|
||||
<span style="display: inline-block; width: 100%; " class="px-4" onClick={props.handler.bind(null, item)}>
|
||||
<span class="inline-block w-full px-4" onClick={props.handler.bind(null, item)}>
|
||||
{props.showIcon && item.icon && <Icon class="mr-2" icon={item.icon} />}
|
||||
<span>{item.label}</span>
|
||||
</span>
|
||||
|
|
|
@ -3,7 +3,6 @@ import { ref, watch } from 'vue'
|
|||
import { Input } from 'ant-design-vue'
|
||||
import CronTabModal from './CronTabModal.vue'
|
||||
import { cronEmits, cronProps } from './cron.data'
|
||||
import { useDesign } from '@/hooks/web/useDesign'
|
||||
import { useModal } from '@/components/Modal'
|
||||
import { propTypes } from '@/utils/propTypes'
|
||||
import { Icon } from '@/components/Icon'
|
||||
|
@ -14,7 +13,6 @@ const props = defineProps({
|
|||
exeStartTime: propTypes.oneOfType([propTypes.number, propTypes.string, propTypes.object]).def(0),
|
||||
})
|
||||
const emit = defineEmits([...cronEmits])
|
||||
const { prefixCls } = useDesign('cron-input')
|
||||
const [registerModal, { openModal }] = useModal()
|
||||
const editCronValue = ref(props.value)
|
||||
|
||||
|
@ -37,11 +35,11 @@ function showConfigModal() {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div :class="`${prefixCls}`">
|
||||
<div>
|
||||
<Input v-model:value="editCronValue" :placeholder="placeholder" :disabled="disabled">
|
||||
<template #addonAfter>
|
||||
<a class="open-btn" :disabled="disabled ? 'disabled' : null" @click="showConfigModal">
|
||||
<Icon icon="ant-design:setting-outlined" />
|
||||
<a class="cursor-pointer" :disabled="disabled ? 'disabled' : null" @click="showConfigModal">
|
||||
<Icon class="relative right-0.5 top-0.25" icon="ant-design:setting-outlined" />
|
||||
<span>选择</span>
|
||||
</a>
|
||||
</template>
|
||||
|
@ -56,19 +54,3 @@ function showConfigModal() {
|
|||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="less">
|
||||
@prefix-cls: ~'@{namespace}-cron-input';
|
||||
|
||||
.@{prefix-cls} {
|
||||
a.open-btn {
|
||||
cursor: pointer;
|
||||
|
||||
.app-iconify {
|
||||
position: relative;
|
||||
top: 1px;
|
||||
right: 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<script lang="ts" setup>
|
||||
import type { CSSProperties } from 'vue'
|
||||
import { computed, ref, unref, watch, watchEffect } from 'vue'
|
||||
import { Avatar } from 'ant-design-vue'
|
||||
import CopperModal from './CopperModal.vue'
|
||||
import { useDesign } from '@/hooks/web/useDesign'
|
||||
import { useModal } from '@/components/Modal'
|
||||
|
@ -65,9 +66,9 @@ defineExpose({ openModal: openModal.bind(null, true), closeModal })
|
|||
<div :class="`${prefixCls}-image-mask`" :style="getImageWrapperStyle">
|
||||
<Icon icon="ant-design:cloud-upload-outlined" :size="getIconWidth" :style="getImageWrapperStyle" color="#d6d6d6" />
|
||||
</div>
|
||||
<img v-if="sourceValue" :src="sourceValue" alt="avatar">
|
||||
<Avatar v-if="sourceValue" :size="{ xs: 24, sm: 32, md: 40, lg: 64, xl: 80, xxl: 100 }" :src="sourceValue" alt="avatar" />
|
||||
</div>
|
||||
<a-button v-if="showBtn" :class="`${prefixCls}-upload-btn`" v-bind="btnProps" @click="openModal">
|
||||
<a-button v-if="showBtn" class="mx-auto my-2.5" v-bind="btnProps" @click="openModal">
|
||||
{{ btnText ? btnText : t('component.cropper.selectImage') }}
|
||||
</a-button>
|
||||
|
||||
|
@ -113,9 +114,5 @@ defineExpose({ openModal: openModal.bind(null, true), closeModal })
|
|||
&-image-mask:hover {
|
||||
opacity: 40;
|
||||
}
|
||||
|
||||
&-upload-btn {
|
||||
margin: 10px auto;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
import type { CSSProperties } from 'vue'
|
||||
import { computed } from 'vue'
|
||||
import { footerProps } from '../props'
|
||||
import { useDesign } from '@/hooks/web/useDesign'
|
||||
|
||||
defineOptions({ name: 'BasicDrawerFooter' })
|
||||
|
||||
|
@ -15,8 +14,6 @@ const props = defineProps({
|
|||
})
|
||||
const emit = defineEmits(['ok', 'close'])
|
||||
|
||||
const { prefixCls } = useDesign('basic-drawer-footer')
|
||||
|
||||
const getStyle = computed((): CSSProperties => {
|
||||
const heightStr = `${props.height}`
|
||||
return {
|
||||
|
@ -35,14 +32,21 @@ function handleClose() {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="showFooter || $slots.footer" :class="prefixCls" :style="getStyle">
|
||||
<div
|
||||
v-if="showFooter || $slots.footer"
|
||||
class="absolute bottom-0 w-full border-t-1 border-light-200 bg-white pl-5 pr-3 dark:bg-dark"
|
||||
:style="getStyle"
|
||||
>
|
||||
<template v-if="!$slots.footer">
|
||||
<slot name="insertFooter" />
|
||||
<a-button v-if="showCancelBtn" v-bind="cancelButtonProps" class="mr-2" @click="handleClose">
|
||||
{{ cancelText }}
|
||||
</a-button>
|
||||
<slot name="centerFooter" />
|
||||
<a-button v-if="showOkBtn" :type="okType" v-bind="okButtonProps" class="mr-2" :loading="confirmLoading" @click="handleOk">
|
||||
<a-button
|
||||
v-if="showOkBtn" :type="okType" v-bind="okButtonProps" class="mr-2" :loading="confirmLoading"
|
||||
@click="handleOk"
|
||||
>
|
||||
{{ okText }}
|
||||
</a-button>
|
||||
<slot name="appendFooter" />
|
||||
|
@ -53,21 +57,3 @@ function handleClose() {
|
|||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="less">
|
||||
@prefix-cls: ~'@{namespace}-basic-drawer-footer';
|
||||
@footer-height: 60px;
|
||||
.@{prefix-cls} {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
padding: 0 12px 0 20px;
|
||||
text-align: right;
|
||||
background-color: var(--component-background);
|
||||
border-top: 1px solid var(--border-color);
|
||||
|
||||
> * {
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
<script lang="ts" setup>
|
||||
import { ArrowLeftOutlined } from '@ant-design/icons-vue'
|
||||
import { BasicTitle } from '@/components/Basic'
|
||||
import { useDesign } from '@/hooks/web/useDesign'
|
||||
import { propTypes } from '@/utils/propTypes'
|
||||
|
||||
defineOptions({ name: 'BasicDrawerHeader' })
|
||||
|
@ -13,52 +12,27 @@ defineProps({
|
|||
})
|
||||
const emit = defineEmits(['close'])
|
||||
|
||||
const { prefixCls } = useDesign('basic-drawer-header')
|
||||
|
||||
function handleClose() {
|
||||
emit('close')
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BasicTitle v-if="!isDetail" :class="prefixCls">
|
||||
<BasicTitle v-if="!isDetail" class="h-full flex items-center">
|
||||
<slot name="title" />
|
||||
{{ !$slots.title ? title : '' }}
|
||||
</BasicTitle>
|
||||
|
||||
<div v-else :class="[prefixCls, `${prefixCls}--detail`]">
|
||||
<span :class="`${prefixCls}__twrap`">
|
||||
<div v-else>
|
||||
<span class="flex-1">
|
||||
<span v-if="showDetailBack" @click="handleClose">
|
||||
<ArrowLeftOutlined :class="`${prefixCls}__back`" />
|
||||
<ArrowLeftOutlined class="cursor-pointer px-3" />
|
||||
</span>
|
||||
<span v-if="title">{{ title }}</span>
|
||||
</span>
|
||||
|
||||
<span :class="`${prefixCls}__toolbar`">
|
||||
<span class="pr-12.5">
|
||||
<slot name="titleToolbar" />
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="less">
|
||||
@prefix-cls: ~'@{namespace}-basic-drawer-header';
|
||||
@footer-height: 60px;
|
||||
.@{prefix-cls} {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
|
||||
&__back {
|
||||
padding: 0 12px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&__twrap {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
&__toolbar {
|
||||
padding-right: 50px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -280,11 +280,11 @@ function getFileName(path) {
|
|||
<Upload
|
||||
:headers="headers"
|
||||
:multiple="multiple"
|
||||
:action="uploadUrl as any"
|
||||
:action="uploadUrl"
|
||||
:file-list="fileList"
|
||||
:disabled="disabled"
|
||||
v-bind="bindProps"
|
||||
@remove="onRemove as any"
|
||||
@remove="onRemove"
|
||||
@change="onFileChange"
|
||||
@preview="onFilePreview"
|
||||
>
|
||||
|
@ -305,7 +305,6 @@ function getFileName(path) {
|
|||
</template>
|
||||
|
||||
<style lang="less">
|
||||
//noinspection LessUnresolvedVariable
|
||||
@prefix-cls: ~'@{namespace}-upload';
|
||||
|
||||
.@{prefix-cls} {
|
||||
|
@ -323,12 +322,9 @@ function getFileName(path) {
|
|||
}
|
||||
}
|
||||
|
||||
/* update-begin-author:taoyan date:2022-5-24 for:VUEN-1093详情界面 图片下载按钮显示不全 */
|
||||
.upload-download-handler {
|
||||
right: 6px !important;
|
||||
}
|
||||
|
||||
/* update-end-author:taoyan date:2022-5-24 for:VUEN-1093详情界面 图片下载按钮显示不全 */
|
||||
}
|
||||
|
||||
.ant-upload-list-item {
|
||||
|
|
|
@ -140,7 +140,8 @@ export default defineComponent({
|
|||
const { rulesMessageJoinLabel: globalRulesMessageJoinLabel } = props.formProps
|
||||
|
||||
const joinLabel = Reflect.has(props.schema, 'rulesMessageJoinLabel') ? rulesMessageJoinLabel : globalRulesMessageJoinLabel
|
||||
const defaultMsg = `${createPlaceholderMessage(component)}${joinLabel ? label : ''}`
|
||||
const assertLabel = joinLabel ? label : ''
|
||||
const defaultMsg = component ? createPlaceholderMessage(component) + assertLabel : assertLabel
|
||||
|
||||
function validator(rule: any, value: any) {
|
||||
const msg = rule.message || defaultMsg
|
||||
|
@ -354,8 +355,8 @@ export default defineComponent({
|
|||
}
|
||||
|
||||
return () => {
|
||||
const { colProps = {}, colSlot, renderColContent, component } = props.schema
|
||||
if (!componentMap.has(component))
|
||||
const { colProps = {}, colSlot, renderColContent, component, slot } = props.schema
|
||||
if (!componentMap.has(component) && !slot)
|
||||
return null
|
||||
|
||||
const { baseColProps = {} } = props.formProps
|
||||
|
|
|
@ -119,7 +119,7 @@ export default defineComponent({
|
|||
|
||||
<template>
|
||||
<div class="v-form-container">
|
||||
<Form ref="eFormModel" class="v-form-model" :model="formModel" v-bind="formModelProps">
|
||||
<Form ref="eFormModel" class="overflow-hidden" :model="formModel" v-bind="formModelProps">
|
||||
<Row>
|
||||
<FormRender
|
||||
v-for="(schema, index) of noHiddenList"
|
||||
|
@ -143,9 +143,3 @@ export default defineComponent({
|
|||
</Form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.v-form-model {
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,22 +1,9 @@
|
|||
<!--
|
||||
* @Description: 组件属性控件
|
||||
-->
|
||||
<script lang="ts">
|
||||
import {
|
||||
Checkbox,
|
||||
Col,
|
||||
Empty,
|
||||
Form,
|
||||
FormItem,
|
||||
Input,
|
||||
InputNumber,
|
||||
RadioGroup,
|
||||
Row,
|
||||
Select,
|
||||
Switch,
|
||||
} from 'ant-design-vue'
|
||||
import RadioButtonGroup from '/@/components/Form/src/components/RadioButtonGroup.vue'
|
||||
import { computed, defineComponent, ref, watch } from 'vue'
|
||||
<script lang="ts" setup>
|
||||
import { Checkbox, Col, Empty, Form, FormItem, Select } from 'ant-design-vue'
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import { useFormDesignState } from '../../../hooks/useFormDesignState'
|
||||
import {
|
||||
baseComponentAttrs,
|
||||
|
@ -28,145 +15,116 @@ import { formItemsForEach, remove } from '../../../utils'
|
|||
import type { IBaseFormAttrs } from '../config/formItemPropsConfig'
|
||||
import FormOptions from './FormOptions.vue'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'ComponentProps',
|
||||
components: {
|
||||
FormOptions,
|
||||
Empty,
|
||||
Input,
|
||||
Form,
|
||||
FormItem,
|
||||
Switch,
|
||||
Checkbox,
|
||||
Select,
|
||||
InputNumber,
|
||||
RadioGroup,
|
||||
RadioButtonGroup,
|
||||
Col,
|
||||
Row,
|
||||
const { formConfig } = useFormDesignState()
|
||||
// 让compuated属性自动更新
|
||||
const allOptions = ref([] as Omit<IBaseFormAttrs, 'tag'>[])
|
||||
function showControlAttrs(includes: string[] | undefined) {
|
||||
if (!includes)
|
||||
return true
|
||||
return includes.includes(formConfig.value.currentItem!.component)
|
||||
}
|
||||
|
||||
if (formConfig.value.currentItem) {
|
||||
formConfig.value.currentItem.componentProps
|
||||
= formConfig.value.currentItem.componentProps || {}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => formConfig.value.currentItem?.field,
|
||||
(_newValue, oldValue) => {
|
||||
formConfig.value.schemas
|
||||
&& formItemsForEach(formConfig.value.schemas, (item) => {
|
||||
if (item.link) {
|
||||
const index = item.link.findIndex(linkItem => linkItem === oldValue)
|
||||
index !== -1 && remove(item.link, index)
|
||||
}
|
||||
})
|
||||
},
|
||||
setup() {
|
||||
// 让compuated属性自动更新
|
||||
)
|
||||
|
||||
const allOptions = ref([] as Omit<IBaseFormAttrs, 'tag'>[])
|
||||
const showControlAttrs = (includes: string[] | undefined) => {
|
||||
if (!includes)
|
||||
return true
|
||||
return includes.includes(formConfig.value.currentItem!.component)
|
||||
}
|
||||
watch(
|
||||
() => formConfig.value.currentItem && formConfig.value.currentItem.component,
|
||||
() => {
|
||||
allOptions.value = []
|
||||
baseComponentControlAttrs.forEach((item) => {
|
||||
item.category = 'control'
|
||||
if (!item.includes) {
|
||||
// 如果属性没有include,所有的控件都适用
|
||||
|
||||
const { formConfig } = useFormDesignState()
|
||||
allOptions.value.push(item)
|
||||
}
|
||||
else if (item.includes.includes(formConfig.value.currentItem!.component)) {
|
||||
// 如果有include,检查是否包含了当前控件类型
|
||||
allOptions.value.push(item)
|
||||
}
|
||||
})
|
||||
|
||||
if (formConfig.value.currentItem) {
|
||||
formConfig.value.currentItem.componentProps
|
||||
= formConfig.value.currentItem.componentProps || {}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => formConfig.value.currentItem?.field,
|
||||
(_newValue, oldValue) => {
|
||||
formConfig.value.schemas
|
||||
&& formItemsForEach(formConfig.value.schemas, (item) => {
|
||||
if (item.link) {
|
||||
const index = item.link.findIndex(linkItem => linkItem === oldValue)
|
||||
index !== -1 && remove(item.link, index)
|
||||
}
|
||||
})
|
||||
},
|
||||
)
|
||||
|
||||
watch(
|
||||
() => formConfig.value.currentItem && formConfig.value.currentItem.component,
|
||||
() => {
|
||||
allOptions.value = []
|
||||
baseComponentControlAttrs.forEach((item) => {
|
||||
item.category = 'control'
|
||||
if (!item.includes) {
|
||||
// 如果属性没有include,所有的控件都适用
|
||||
baseComponentCommonAttrs.forEach((item) => {
|
||||
item.category = 'input'
|
||||
if (item.includes) {
|
||||
if (item.includes.includes(formConfig.value.currentItem!.component))
|
||||
allOptions.value.push(item)
|
||||
}
|
||||
else if (item.exclude) {
|
||||
if (!item.exclude.includes(formConfig.value.currentItem!.component))
|
||||
allOptions.value.push(item)
|
||||
}
|
||||
else {
|
||||
allOptions.value.push(item)
|
||||
}
|
||||
})
|
||||
|
||||
baseComponentAttrs[formConfig.value.currentItem!.component]
|
||||
&& baseComponentAttrs[formConfig.value.currentItem!.component].forEach(async (item) => {
|
||||
if (item.component) {
|
||||
if (['Switch', 'Checkbox', 'Radio'].includes(item.component)) {
|
||||
item.category = 'control'
|
||||
allOptions.value.push(item)
|
||||
}
|
||||
else if (item.includes.includes(formConfig.value.currentItem!.component)) {
|
||||
// 如果有include,检查是否包含了当前控件类型
|
||||
allOptions.value.push(item)
|
||||
}
|
||||
})
|
||||
|
||||
baseComponentCommonAttrs.forEach((item) => {
|
||||
item.category = 'input'
|
||||
if (item.includes) {
|
||||
if (item.includes.includes(formConfig.value.currentItem!.component))
|
||||
allOptions.value.push(item)
|
||||
}
|
||||
else if (item.exclude) {
|
||||
if (!item.exclude.includes(formConfig.value.currentItem!.component))
|
||||
allOptions.value.push(item)
|
||||
}
|
||||
else {
|
||||
item.category = 'input'
|
||||
allOptions.value.push(item)
|
||||
}
|
||||
})
|
||||
|
||||
baseComponentAttrs[formConfig.value.currentItem!.component]
|
||||
&& baseComponentAttrs[formConfig.value.currentItem!.component].forEach(async (item) => {
|
||||
if (item.component) {
|
||||
if (['Switch', 'Checkbox', 'Radio'].includes(item.component)) {
|
||||
item.category = 'control'
|
||||
allOptions.value.push(item)
|
||||
}
|
||||
else {
|
||||
item.category = 'input'
|
||||
allOptions.value.push(item)
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
},
|
||||
)
|
||||
// 控制性的选项
|
||||
const controlOptions = computed(() => {
|
||||
return allOptions.value.filter((item) => {
|
||||
return item.category === 'control'
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
// 非控制性选择
|
||||
const inputOptions = computed(() => {
|
||||
return allOptions.value.filter((item) => {
|
||||
return item.category === 'input'
|
||||
})
|
||||
})
|
||||
|
||||
watch(
|
||||
() => formConfig.value.currentItem!.componentProps,
|
||||
() => {
|
||||
const func = componentPropsFuncs[formConfig.value.currentItem!.component]
|
||||
if (func)
|
||||
func(formConfig.value.currentItem!.componentProps, allOptions.value)
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
deep: true,
|
||||
},
|
||||
)
|
||||
const linkOptions = computed(() => {
|
||||
return (
|
||||
formConfig.value.schemas
|
||||
&& formConfig.value.schemas
|
||||
.filter(item => item.key !== formConfig.value.currentItem!.key)
|
||||
.map(({ label, field }) => ({ label: `${label}/${field}`, value: field }))
|
||||
)
|
||||
})
|
||||
return {
|
||||
formConfig,
|
||||
showControlAttrs,
|
||||
linkOptions,
|
||||
controlOptions,
|
||||
inputOptions,
|
||||
}
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
},
|
||||
)
|
||||
// 控制性的选项
|
||||
const controlOptions = computed(() => {
|
||||
return allOptions.value.filter((item) => {
|
||||
return item.category === 'control'
|
||||
})
|
||||
})
|
||||
|
||||
// 非控制性选择
|
||||
const inputOptions = computed(() => {
|
||||
return allOptions.value.filter((item) => {
|
||||
return item.category === 'input'
|
||||
})
|
||||
})
|
||||
|
||||
watch(
|
||||
() => formConfig.value.currentItem!.componentProps,
|
||||
() => {
|
||||
const func = componentPropsFuncs[formConfig.value.currentItem!.component]
|
||||
if (func)
|
||||
func(formConfig.value.currentItem!.componentProps, allOptions.value)
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
deep: true,
|
||||
},
|
||||
)
|
||||
const linkOptions = computed(() => {
|
||||
return (
|
||||
formConfig.value.schemas
|
||||
&& formConfig.value.schemas
|
||||
.filter(item => item.key !== formConfig.value.currentItem!.key)
|
||||
.map(({ label, field }) => ({ label: `${label}/${field}`, value: field }))
|
||||
)
|
||||
})
|
||||
</script>
|
||||
|
||||
|
@ -184,27 +142,20 @@ export default defineComponent({
|
|||
|
||||
<div v-if="item.children">
|
||||
<component
|
||||
v-bind="child.componentProps"
|
||||
:is="child.component"
|
||||
v-for="(child, index) of item.children"
|
||||
:key="index"
|
||||
v-model:value="formConfig.currentItem.componentProps[item.name][index]"
|
||||
v-bind="child.componentProps" :is="child.component" v-for="(child, index) of item.children"
|
||||
:key="index" v-model:value="formConfig.currentItem.componentProps[item.name][index]"
|
||||
/>
|
||||
</div>
|
||||
<!-- 如果不是数组,则正常处理属性值 -->
|
||||
<component
|
||||
v-bind="item.componentProps"
|
||||
:is="item.component"
|
||||
v-else
|
||||
v-model:value="formConfig.currentItem.componentProps[item.name]"
|
||||
class="component-prop"
|
||||
v-bind="item.componentProps" :is="item.component" v-else
|
||||
v-model:value="formConfig.currentItem.componentProps[item.name]" class="component-prop"
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem label="控制属性">
|
||||
<Col v-for="item in controlOptions" :key="item.name">
|
||||
<Checkbox
|
||||
v-if="showControlAttrs(item.includes)"
|
||||
v-bind="item.componentProps"
|
||||
v-if="showControlAttrs(item.includes)" v-bind="item.componentProps"
|
||||
v-model:checked="formConfig.currentItem.componentProps[item.name]"
|
||||
>
|
||||
{{ item.label }}
|
||||
|
@ -213,25 +164,19 @@ export default defineComponent({
|
|||
</FormItem>
|
||||
</div>
|
||||
<FormItem label="关联字段">
|
||||
<Select
|
||||
v-model:value="formConfig.currentItem.link"
|
||||
mode="multiple"
|
||||
:options="linkOptions"
|
||||
/>
|
||||
<Select v-model:value="formConfig.currentItem.link" mode="multiple" :options="linkOptions" />
|
||||
</FormItem>
|
||||
|
||||
<FormItem
|
||||
v-if="
|
||||
[
|
||||
'Select',
|
||||
'CheckboxGroup',
|
||||
'RadioGroup',
|
||||
'TreeSelect',
|
||||
'Cascader',
|
||||
'AutoComplete',
|
||||
].includes(formConfig.currentItem.component)
|
||||
"
|
||||
label="选项"
|
||||
v-if="[
|
||||
'Select',
|
||||
'CheckboxGroup',
|
||||
'RadioGroup',
|
||||
'TreeSelect',
|
||||
'Cascader',
|
||||
'AutoComplete',
|
||||
].includes(formConfig.currentItem.component)
|
||||
" label="选项"
|
||||
>
|
||||
<FormOptions />
|
||||
</FormItem>
|
||||
|
|
|
@ -1,45 +1,20 @@
|
|||
<!--
|
||||
* @Description: 表单项属性
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
import { Checkbox, Empty, Form, FormItem, Input, Select, Slider, Switch } from 'ant-design-vue'
|
||||
<script lang="ts" setup>
|
||||
import { Empty, Form, FormItem } from 'ant-design-vue'
|
||||
import { isArray } from 'lodash-es'
|
||||
import { baseItemColumnProps } from '../config/formItemPropsConfig'
|
||||
|
||||
import { useFormDesignState } from '../../../hooks/useFormDesignState'
|
||||
import RuleProps from './RuleProps.vue'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'FormItemProps',
|
||||
components: {
|
||||
RuleProps,
|
||||
Empty,
|
||||
Input,
|
||||
Form,
|
||||
FormItem,
|
||||
Switch,
|
||||
Checkbox,
|
||||
Select,
|
||||
Slider,
|
||||
},
|
||||
// props: {} as PropsOptions,
|
||||
const { formConfig } = useFormDesignState()
|
||||
function showProps(exclude: string[] | undefined) {
|
||||
if (!exclude)
|
||||
return true
|
||||
|
||||
setup() {
|
||||
const { formConfig } = useFormDesignState()
|
||||
const showProps = (exclude: string[] | undefined) => {
|
||||
if (!exclude)
|
||||
return true
|
||||
|
||||
return isArray(exclude) ? !exclude.includes(formConfig.value.currentItem!.component) : true
|
||||
}
|
||||
return {
|
||||
baseItemColumnProps,
|
||||
formConfig,
|
||||
showProps,
|
||||
}
|
||||
},
|
||||
})
|
||||
return isArray(exclude) ? !exclude.includes(formConfig.value.currentItem!.component) : true
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -50,11 +25,8 @@ export default defineComponent({
|
|||
<div v-for="item of baseItemColumnProps" :key="item.name">
|
||||
<FormItem v-if="showProps(item.exclude)" :label="item.label">
|
||||
<component
|
||||
v-bind="item.componentProps"
|
||||
:is="item.component"
|
||||
v-if="formConfig.currentItem.colProps"
|
||||
v-model:value="formConfig.currentItem.colProps[item.name]"
|
||||
class="component-props"
|
||||
v-bind="item.componentProps" :is="item.component" v-if="formConfig.currentItem.colProps"
|
||||
v-model:value="formConfig.currentItem.colProps[item.name]" class="component-props"
|
||||
/>
|
||||
</FormItem>
|
||||
</div>
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<!--
|
||||
* @Description: 表单项属性,控件属性面板
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, watch } from 'vue'
|
||||
<script lang="ts" setup>
|
||||
import { computed, watch } from 'vue'
|
||||
import {
|
||||
Checkbox,
|
||||
Col,
|
||||
|
@ -10,9 +10,6 @@ import {
|
|||
Form,
|
||||
FormItem,
|
||||
Input,
|
||||
RadioGroup,
|
||||
Select,
|
||||
Slider,
|
||||
Switch,
|
||||
} from 'ant-design-vue'
|
||||
import { isArray } from 'lodash-es'
|
||||
|
@ -26,61 +23,32 @@ import {
|
|||
import { useFormDesignState } from '../../../hooks/useFormDesignState'
|
||||
import RuleProps from './RuleProps.vue'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'FormItemProps',
|
||||
components: {
|
||||
RuleProps,
|
||||
Empty,
|
||||
Input,
|
||||
Form,
|
||||
FormItem,
|
||||
Switch,
|
||||
Checkbox,
|
||||
Select,
|
||||
Slider,
|
||||
Col,
|
||||
RadioGroup,
|
||||
},
|
||||
// props: {} as PropsOptions,
|
||||
const { formConfig } = useFormDesignState()
|
||||
|
||||
setup() {
|
||||
const { formConfig } = useFormDesignState()
|
||||
|
||||
watch(
|
||||
() => formConfig.value,
|
||||
() => {
|
||||
if (formConfig.value.currentItem) {
|
||||
formConfig.value.currentItem.itemProps = formConfig.value.currentItem.itemProps || {}
|
||||
formConfig.value.currentItem.itemProps.labelCol
|
||||
watch(
|
||||
() => formConfig.value,
|
||||
() => {
|
||||
if (formConfig.value.currentItem) {
|
||||
formConfig.value.currentItem.itemProps = formConfig.value.currentItem.itemProps || {}
|
||||
formConfig.value.currentItem.itemProps.labelCol
|
||||
= formConfig.value.currentItem.itemProps.labelCol || {}
|
||||
formConfig.value.currentItem.itemProps.wrapperCol
|
||||
formConfig.value.currentItem.itemProps.wrapperCol
|
||||
= formConfig.value.currentItem.itemProps.wrapperCol || {}
|
||||
}
|
||||
},
|
||||
{ deep: true, immediate: true },
|
||||
)
|
||||
const showProps = (exclude: string[] | undefined) => {
|
||||
if (!exclude)
|
||||
return true
|
||||
|
||||
return isArray(exclude) ? !exclude.includes(formConfig.value.currentItem!.component) : true
|
||||
}
|
||||
|
||||
const controlPropsList = computed(() => {
|
||||
return baseFormItemControlAttrs.filter((item) => {
|
||||
return showProps(item.exclude)
|
||||
})
|
||||
})
|
||||
|
||||
return {
|
||||
baseFormItemProps,
|
||||
advanceFormItemProps,
|
||||
advanceFormItemColProps,
|
||||
formConfig,
|
||||
controlPropsList,
|
||||
showProps,
|
||||
}
|
||||
},
|
||||
{ deep: true, immediate: true },
|
||||
)
|
||||
function showProps(exclude: string[] | undefined) {
|
||||
if (!exclude)
|
||||
return true
|
||||
|
||||
return isArray(exclude) ? !exclude.includes(formConfig.value.currentItem!.component) : true
|
||||
}
|
||||
|
||||
const controlPropsList = computed(() => {
|
||||
return baseFormItemControlAttrs.filter((item) => {
|
||||
return showProps(item.exclude)
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
|
|
|
@ -1,42 +1,29 @@
|
|||
<!--
|
||||
* @Description: 拖拽节点控件
|
||||
-->
|
||||
<script lang="ts">
|
||||
<script lang="ts" setup>
|
||||
import type { PropType } from 'vue'
|
||||
import { defineComponent, reactive, toRefs } from 'vue'
|
||||
import type { IVFormComponent } from '../../../typings/v-form-component'
|
||||
import { useFormDesignState } from '../../../hooks/useFormDesignState'
|
||||
import VFormItem from '../../VFormItem/index.vue'
|
||||
import FormNodeOperate from './FormNodeOperate.vue'
|
||||
|
||||
// import VFormItem from '../../VFormItem/vFormItem.vue';
|
||||
export default defineComponent({
|
||||
name: 'FormNode',
|
||||
components: {
|
||||
VFormItem,
|
||||
FormNodeOperate,
|
||||
},
|
||||
props: {
|
||||
const props = defineProps(
|
||||
{
|
||||
schema: {
|
||||
type: Object as PropType<IVFormComponent>,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const { formConfig, formDesignMethods } = useFormDesignState()
|
||||
const state = reactive({})
|
||||
// 获取 formDesignMethods
|
||||
const handleSelectItem = () => {
|
||||
// 调用 formDesignMethods
|
||||
formDesignMethods.handleSetSelectItem(props.schema)
|
||||
}
|
||||
return {
|
||||
...toRefs(state),
|
||||
handleSelectItem,
|
||||
formConfig,
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
)
|
||||
|
||||
const { formConfig, formDesignMethods } = useFormDesignState()
|
||||
// 获取 formDesignMethods
|
||||
function handleSelectItem() {
|
||||
// 调用 formDesignMethods
|
||||
formDesignMethods.handleSetSelectItem(props.schema)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
@ -52,10 +52,10 @@ function deleteGridOptions(index: number) {
|
|||
</div>
|
||||
<div v-else>
|
||||
<div v-for="(item, index) of formConfig.currentItem!.componentProps![key]" :key="index">
|
||||
<div class="options-box">
|
||||
<div class="mb-1.5 flex items-center">
|
||||
<Input v-model:value="item.label" />
|
||||
<Input v-model:value="item.value" class="options-value" />
|
||||
<a class="options-delete" @click="deleteOptions(index)">
|
||||
<Input v-model:value="item.value" class="mx-2" />
|
||||
<a class="h-7.5 w-7.5 rounded-full bg-light-50 text-center text-gray-500 hover:bg-red-500" @click="deleteOptions(index)">
|
||||
<Icon icon="ant-design:delete-outlined" />
|
||||
</a>
|
||||
</div>
|
||||
|
@ -67,30 +67,3 @@ function deleteGridOptions(index: number) {
|
|||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.options-box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 5px;
|
||||
|
||||
.options-value {
|
||||
margin: 0 8px;
|
||||
}
|
||||
|
||||
.options-delete {
|
||||
flex-shrink: 0;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
color: #666;
|
||||
text-align: center;
|
||||
background: #f5f5f5;
|
||||
border-radius: 50%;
|
||||
|
||||
&:hover {
|
||||
background: #ff4d4f;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -109,7 +109,7 @@ defineExpose({ showModal })
|
|||
取消
|
||||
</a-button>
|
||||
<Upload
|
||||
class="upload-button"
|
||||
class="mx-2.5"
|
||||
:before-upload="beforeUpload"
|
||||
:show-upload-list="false"
|
||||
accept="application/json"
|
||||
|
@ -124,9 +124,3 @@ defineExpose({ showModal })
|
|||
</template>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.upload-button {
|
||||
margin: 0 10px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
* 千万不要在template下面的第一行加注释,因为这里拖动的第一个元素
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
<script lang="ts" setup>
|
||||
import type { PropType } from 'vue'
|
||||
import { computed, defineComponent, reactive, toRefs } from 'vue'
|
||||
import { computed } from 'vue'
|
||||
import draggable from 'vuedraggable'
|
||||
import { Col, Row } from 'ant-design-vue'
|
||||
import { useFormDesignState } from '../../../hooks/useFormDesignState'
|
||||
|
@ -13,16 +13,8 @@ import type { IVFormComponent } from '../../../typings/v-form-component'
|
|||
import FormNode from './FormNode.vue'
|
||||
import FormNodeOperate from './FormNodeOperate.vue'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'LayoutItem',
|
||||
components: {
|
||||
FormNode,
|
||||
FormNodeOperate,
|
||||
Draggable: draggable,
|
||||
Row,
|
||||
Col,
|
||||
},
|
||||
props: {
|
||||
const props = defineProps(
|
||||
{
|
||||
schema: {
|
||||
type: Object as PropType<IVFormComponent>,
|
||||
required: true,
|
||||
|
@ -32,33 +24,23 @@ export default defineComponent({
|
|||
required: true,
|
||||
},
|
||||
},
|
||||
emits: ['dragStart', 'handleColAdd', 'handle-copy', 'handle-delete'],
|
||||
setup(props) {
|
||||
const {
|
||||
formDesignMethods: { handleSetSelectItem },
|
||||
formConfig,
|
||||
} = useFormDesignState()
|
||||
const state = reactive({})
|
||||
const colPropsComputed = computed(() => {
|
||||
const { colProps = {} } = props.schema
|
||||
return colProps
|
||||
})
|
||||
)
|
||||
|
||||
const list1 = computed(() => props.schema.columns)
|
||||
const emit = defineEmits(['dragStart', 'handleColAdd', 'handle-copy', 'handle-delete'])
|
||||
|
||||
// 计算布局元素,水平模式下为ACol,非水平模式下为div
|
||||
const layoutTag = computed(() => {
|
||||
return formConfig.value.layout === 'horizontal' ? 'Col' : 'div'
|
||||
})
|
||||
const Draggable = draggable
|
||||
|
||||
return {
|
||||
...toRefs(state),
|
||||
colPropsComputed,
|
||||
handleSetSelectItem,
|
||||
layoutTag,
|
||||
list1,
|
||||
}
|
||||
},
|
||||
const { formDesignMethods: { handleSetSelectItem }, formConfig } = useFormDesignState()
|
||||
const colPropsComputed = computed(() => {
|
||||
const { colProps = {} } = props.schema
|
||||
return colProps
|
||||
})
|
||||
|
||||
const list1 = computed(() => props.schema.columns)
|
||||
|
||||
// 计算布局元素,水平模式下为ACol,非水平模式下为div
|
||||
const layoutTag = computed(() => {
|
||||
return formConfig.value.layout === 'horizontal' ? 'Col' : 'div'
|
||||
})
|
||||
</script>
|
||||
|
||||
|
@ -87,8 +69,8 @@ export default defineComponent({
|
|||
class="drag-move"
|
||||
:schema="element"
|
||||
:current-item="currentItem"
|
||||
@handle-copy="$emit('handle-copy')"
|
||||
@handle-delete="$emit('handle-delete')"
|
||||
@handle-copy="emit('handle-copy')"
|
||||
@handle-delete="emit('handle-delete')"
|
||||
/>
|
||||
</template>
|
||||
</Draggable>
|
||||
|
@ -102,8 +84,8 @@ export default defineComponent({
|
|||
:key="schema.key"
|
||||
:schema="schema"
|
||||
:current-item="currentItem"
|
||||
@handle-copy="$emit('handle-copy')"
|
||||
@handle-delete="$emit('handle-delete')"
|
||||
@handle-copy="emit('handle-copy')"
|
||||
@handle-delete="emit('handle-delete')"
|
||||
/>
|
||||
</Col>
|
||||
</template>
|
||||
|
|
|
@ -1,16 +1,12 @@
|
|||
<script lang="ts">
|
||||
import { defineComponent, reactive, ref, toRefs, unref } from 'vue'
|
||||
<script lang="ts" setup>
|
||||
import { ref, unref } from 'vue'
|
||||
import { CodeEditor, MODE } from '@/components/CodeEditor'
|
||||
|
||||
import { useCopyToClipboard } from '@/hooks/web/useCopyToClipboard'
|
||||
import { useMessage } from '@/hooks/web/useMessage'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'PreviewCode',
|
||||
components: {
|
||||
CodeEditor,
|
||||
},
|
||||
props: {
|
||||
const props = defineProps(
|
||||
{
|
||||
fileFormat: {
|
||||
type: String,
|
||||
default: 'json',
|
||||
|
@ -20,51 +16,37 @@ export default defineComponent({
|
|||
default: '',
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const state = reactive({
|
||||
open: false,
|
||||
})
|
||||
)
|
||||
|
||||
const myEditor = ref(null)
|
||||
const myEditor = ref(null)
|
||||
|
||||
const exportData = (data: string, fileName = `file.${props.fileFormat}`) => {
|
||||
let content = 'data:text/csv;charset=utf-8,'
|
||||
content += data
|
||||
const encodedUri = encodeURI(content)
|
||||
const actions = document.createElement('a')
|
||||
actions.setAttribute('href', encodedUri)
|
||||
actions.setAttribute('download', fileName)
|
||||
actions.click()
|
||||
}
|
||||
function exportData(data: string, fileName = `file.${props.fileFormat}`) {
|
||||
let content = 'data:text/csv;charset=utf-8,'
|
||||
content += data
|
||||
const encodedUri = encodeURI(content)
|
||||
const actions = document.createElement('a')
|
||||
actions.setAttribute('href', encodedUri)
|
||||
actions.setAttribute('download', fileName)
|
||||
actions.click()
|
||||
}
|
||||
|
||||
const handleExportJson = () => {
|
||||
exportData(props.editorJson)
|
||||
}
|
||||
const { clipboardRef, copiedRef } = useCopyToClipboard()
|
||||
const { createMessage } = useMessage()
|
||||
function handleExportJson() {
|
||||
exportData(props.editorJson)
|
||||
}
|
||||
const { clipboardRef, copiedRef } = useCopyToClipboard()
|
||||
const { createMessage } = useMessage()
|
||||
|
||||
const handleCopyJson = () => {
|
||||
// 复制数据
|
||||
const value = props.editorJson
|
||||
if (!value) {
|
||||
createMessage.warning('代码为空!')
|
||||
return
|
||||
}
|
||||
clipboardRef.value = value
|
||||
if (unref(copiedRef))
|
||||
createMessage.warning('复制成功!')
|
||||
}
|
||||
|
||||
return {
|
||||
...toRefs(state),
|
||||
myEditor,
|
||||
exportData,
|
||||
handleCopyJson,
|
||||
handleExportJson,
|
||||
MODE,
|
||||
}
|
||||
},
|
||||
})
|
||||
function handleCopyJson() {
|
||||
// 复制数据
|
||||
const value = props.editorJson
|
||||
if (!value) {
|
||||
createMessage.warning('代码为空!')
|
||||
return
|
||||
}
|
||||
clipboardRef.value = value
|
||||
if (unref(copiedRef))
|
||||
createMessage.warning('复制成功!')
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -72,10 +54,10 @@ export default defineComponent({
|
|||
<div class="v-json-box">
|
||||
<CodeEditor ref="myEditor" :value="editorJson" :mode="MODE.JSON" />
|
||||
</div>
|
||||
<div class="copy-btn-box">
|
||||
<div class="pt-2 text-center">
|
||||
<a-button
|
||||
type="primary"
|
||||
class="copy-btn"
|
||||
class="mr-2"
|
||||
data-clipboard-action="copy"
|
||||
:data-clipboard-text="editorJson"
|
||||
@click="handleCopyJson"
|
||||
|
@ -88,15 +70,3 @@ export default defineComponent({
|
|||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
// modal复制按钮样式
|
||||
.copy-btn-box {
|
||||
padding-top: 8px;
|
||||
text-align: center;
|
||||
|
||||
.copy-btn {
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -19,7 +19,6 @@ import PropsPanel from './modules/PropsPanel.vue'
|
|||
import ImportJsonModal from './components/ImportJsonModal.vue'
|
||||
import CodeModal from './components/CodeModal.vue'
|
||||
import { globalConfigState } from './config/formItemPropsConfig'
|
||||
import { useDesign } from '@/hooks/web/useDesign'
|
||||
import { CollapseContainer } from '@/components/Container/index'
|
||||
import 'codemirror/mode/javascript/javascript'
|
||||
|
||||
|
@ -29,7 +28,6 @@ defineProps({
|
|||
default: 'v-form-antd表单设计器',
|
||||
},
|
||||
})
|
||||
const { prefixCls } = useDesign('form-design')
|
||||
// 子组件实例
|
||||
const propsPanel = ref<null | IPropsPanel>(null)
|
||||
const jsonModal = ref<null | IToolbarMethods>(null)
|
||||
|
@ -251,7 +249,7 @@ provide<IFormDesignMethods>('formDesignMethods', {
|
|||
<template>
|
||||
<Layout>
|
||||
<LayoutSider
|
||||
:class="`left ${prefixCls}-sider`"
|
||||
class="bg-white dark:bg-black"
|
||||
collapsible
|
||||
collapsed-width="0"
|
||||
width="270"
|
||||
|
@ -302,7 +300,7 @@ provide<IFormDesignMethods>('formDesignMethods', {
|
|||
/>
|
||||
</LayoutContent>
|
||||
<LayoutSider
|
||||
:class="`right ${prefixCls}-sider`"
|
||||
class="bg-white dark:bg-black"
|
||||
collapsible
|
||||
:reverse-arrow="true"
|
||||
collapsed-width="0"
|
||||
|
@ -327,19 +325,3 @@ provide<IFormDesignMethods>('formDesignMethods', {
|
|||
<VFormPreview ref="eFormPreview" :form-config="formConfig" />
|
||||
<VFormPreview2 ref="eFormPreview2" :form-config="formConfig" />
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@prefix-cls: ~'@{namespace}-form-design';
|
||||
|
||||
[data-theme='dark'] {
|
||||
.@{prefix-cls}-sider {
|
||||
background-color: #1f1f1f;
|
||||
}
|
||||
}
|
||||
|
||||
[data-theme='light'] {
|
||||
.@{prefix-cls}-sider {
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,16 +1,13 @@
|
|||
<script lang="ts">
|
||||
import { defineComponent, reactive } from 'vue'
|
||||
<script lang="ts" setup>
|
||||
import draggable from 'vuedraggable'
|
||||
import type { IVFormComponent } from '../../../typings/v-form-component'
|
||||
import { Icon } from '@/components/Icon'
|
||||
import { useDesign } from '@/hooks/web/useDesign'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'CollapseItem',
|
||||
components: { Draggable: draggable, Icon },
|
||||
props: {
|
||||
const props = defineProps(
|
||||
{
|
||||
list: {
|
||||
type: [Array],
|
||||
type: Array as unknown as any[],
|
||||
default: () => [],
|
||||
},
|
||||
handleListPush: {
|
||||
|
@ -18,24 +15,23 @@ export default defineComponent({
|
|||
default: null,
|
||||
},
|
||||
},
|
||||
setup(props, { emit }) {
|
||||
const { prefixCls } = useDesign('form-design-collapse-item')
|
||||
)
|
||||
const emit = defineEmits(['start', 'add-attrs', 'handle-list-push'])
|
||||
const Draggable = draggable
|
||||
|
||||
const state = reactive({})
|
||||
const handleStart = (e: any, list1: IVFormComponent[]) => {
|
||||
emit('start', list1[e.oldIndex].component)
|
||||
}
|
||||
const handleAdd = (e: any) => {
|
||||
console.log(e)
|
||||
}
|
||||
// https://github.com/SortableJS/vue.draggable.next
|
||||
// https://github.com/SortableJS/vue.draggable.next/blob/master/example/components/custom-clone.vue
|
||||
const cloneItem = (one) => {
|
||||
return props.handleListPush(one)
|
||||
}
|
||||
return { prefixCls, state, handleStart, handleAdd, cloneItem }
|
||||
},
|
||||
})
|
||||
const { prefixCls } = useDesign('form-design-collapse-item')
|
||||
|
||||
function handleStart(e: any, list1: IVFormComponent[]) {
|
||||
emit('start', list1[e.oldIndex].component)
|
||||
}
|
||||
function handleAdd(e: any) {
|
||||
console.log(e)
|
||||
}
|
||||
// https://github.com/SortableJS/vue.draggable.next
|
||||
// https://github.com/SortableJS/vue.draggable.next/blob/master/example/components/custom-clone.vue
|
||||
function cloneItem(one) {
|
||||
return props.handleListPush(one)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -57,8 +53,8 @@ export default defineComponent({
|
|||
<template #item="{ element, index }">
|
||||
<li
|
||||
class="bs-box text-ellipsis"
|
||||
@dragstart="$emit('add-attrs', list, index)"
|
||||
@click="$emit('handle-list-push', element)"
|
||||
@dragstart="emit('add-attrs', list, index)"
|
||||
@click="emit('handle-list-push', element)"
|
||||
>
|
||||
<!-- <svg v-if="element.icon.indexOf('icon-') > -1" class="icon" aria-hidden="true">
|
||||
<use :xlink:href="`#${element.icon}`" />
|
||||
|
|
|
@ -2,89 +2,61 @@
|
|||
* @Description: 中间表单布局面板
|
||||
* https://github.com/SortableJS/vue.draggable.next/issues/138
|
||||
-->
|
||||
<script lang="ts">
|
||||
<script lang="ts" setup>
|
||||
import draggable from 'vuedraggable'
|
||||
import { computed, defineComponent } from 'vue'
|
||||
import { computed } from 'vue'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
import { Empty, Form } from 'ant-design-vue'
|
||||
import { useFormDesignState } from '../../../hooks/useFormDesignState'
|
||||
import LayoutItem from '../components/LayoutItem.vue'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'FormComponentPanel',
|
||||
components: {
|
||||
LayoutItem,
|
||||
Draggable: draggable,
|
||||
Form,
|
||||
Empty,
|
||||
},
|
||||
emits: ['handleSetSelectItem'],
|
||||
setup(_, { emit }) {
|
||||
const { formConfig } = useFormDesignState()
|
||||
const emit = defineEmits(['handleSetSelectItem'])
|
||||
|
||||
/**
|
||||
* 拖拽完成事件
|
||||
* @param newIndex
|
||||
*/
|
||||
const addItem = ({ newIndex }: any) => {
|
||||
formConfig.value.schemas = formConfig.value.schemas || []
|
||||
const Draggable = draggable
|
||||
|
||||
const schemas = formConfig.value.schemas
|
||||
schemas[newIndex] = cloneDeep(schemas[newIndex])
|
||||
emit('handleSetSelectItem', schemas[newIndex])
|
||||
}
|
||||
const { formConfig } = useFormDesignState()
|
||||
|
||||
/**
|
||||
* 拖拽开始事件
|
||||
* @param e {Object} 事件对象
|
||||
*/
|
||||
const handleDragStart = (e: any) => {
|
||||
emit('handleSetSelectItem', formConfig.value.schemas[e.oldIndex])
|
||||
}
|
||||
/**
|
||||
* 拖拽完成事件
|
||||
* @param newIndex
|
||||
*/
|
||||
function addItem({ newIndex }: any) {
|
||||
formConfig.value.schemas = formConfig.value.schemas || []
|
||||
|
||||
// 获取祖先组件传递的currentItem
|
||||
const schemas = formConfig.value.schemas
|
||||
schemas[newIndex] = cloneDeep(schemas[newIndex])
|
||||
emit('handleSetSelectItem', schemas[newIndex])
|
||||
}
|
||||
|
||||
// 计算布局元素,水平模式下为ACol,非水平模式下为div
|
||||
const layoutTag = computed(() => {
|
||||
return formConfig.value.layout === 'horizontal' ? 'Col' : 'div'
|
||||
})
|
||||
/**
|
||||
* 拖拽开始事件
|
||||
* @param e {Object} 事件对象
|
||||
*/
|
||||
function handleDragStart(e: any) {
|
||||
emit('handleSetSelectItem', formConfig.value.schemas[e.oldIndex])
|
||||
}
|
||||
|
||||
return {
|
||||
addItem,
|
||||
handleDragStart,
|
||||
formConfig,
|
||||
layoutTag,
|
||||
}
|
||||
},
|
||||
// 获取祖先组件传递的currentItem
|
||||
|
||||
// 计算布局元素,水平模式下为ACol,非水平模式下为div
|
||||
const layoutTag = computed(() => {
|
||||
return formConfig.value.layout === 'horizontal' ? 'Col' : 'div'
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="v-form-container form-panel">
|
||||
<Empty
|
||||
v-show="formConfig.schemas.length === 0"
|
||||
class="empty-text"
|
||||
description="从左侧选择控件添加"
|
||||
/>
|
||||
<Empty v-show="formConfig.schemas.length === 0" class="empty-text" description="从左侧选择控件添加" />
|
||||
<Form v-bind="formConfig">
|
||||
<div class="draggable-box">
|
||||
<Draggable
|
||||
v-model="formConfig.schemas"
|
||||
class="list-main ant-row"
|
||||
group="form-draggable"
|
||||
:component-data="{ name: 'list', tag: 'div', type: 'transition-group' }"
|
||||
ghost-class="moving"
|
||||
:animation="180"
|
||||
handle=".drag-move"
|
||||
item-key="key"
|
||||
@add="addItem"
|
||||
@start="handleDragStart"
|
||||
v-model="formConfig.schemas" class="list-main ant-row" group="form-draggable"
|
||||
:component-data="{ name: 'list', tag: 'div', type: 'transition-group' }" ghost-class="moving" :animation="180"
|
||||
handle=".drag-move" item-key="key" @add="addItem" @start="handleDragStart"
|
||||
>
|
||||
<template #item="{ element }">
|
||||
<LayoutItem
|
||||
class="drag-move"
|
||||
:schema="element"
|
||||
:data="formConfig"
|
||||
class="drag-move" :schema="element" :data="formConfig"
|
||||
:current-item="formConfig.currentItem || {}"
|
||||
/>
|
||||
</template>
|
||||
|
@ -95,72 +67,74 @@ export default defineComponent({
|
|||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@import url('../styles/variable.less');
|
||||
@import url('../styles/drag.less');
|
||||
@import url('../styles/variable.less');
|
||||
@import url('../styles/drag.less');
|
||||
|
||||
.v-form-container {
|
||||
// 内联布局样式
|
||||
.ant-form-inline {
|
||||
.list-main {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-content: flex-start;
|
||||
justify-content: flex-start;
|
||||
.v-form-container {
|
||||
|
||||
.layout-width {
|
||||
width: 100%;
|
||||
}
|
||||
// 内联布局样式
|
||||
.ant-form-inline {
|
||||
.list-main {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-content: flex-start;
|
||||
justify-content: flex-start;
|
||||
|
||||
.layout-width {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-form-item-control-wrapper {
|
||||
min-width: 175px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.form-panel {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
|
||||
.empty-text {
|
||||
position: absolute;
|
||||
inset: -10% 0 0;
|
||||
z-index: 100;
|
||||
height: 150px;
|
||||
margin: auto;
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
.draggable-box {
|
||||
height: calc(100vh - 200px);
|
||||
// width: 100%;
|
||||
overflow: auto;
|
||||
|
||||
.drag-move {
|
||||
min-height: 62px;
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
.list-main {
|
||||
|
||||
// 列表动画
|
||||
.list-enter-active {
|
||||
transition: all 0.5s;
|
||||
}
|
||||
|
||||
.ant-form-item-control-wrapper {
|
||||
min-width: 175px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.form-panel {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
|
||||
.empty-text {
|
||||
position: absolute;
|
||||
inset: -10% 0 0;
|
||||
z-index: 100;
|
||||
height: 150px;
|
||||
margin: auto;
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
.draggable-box {
|
||||
height: calc(100vh - 200px);
|
||||
// width: 100%;
|
||||
overflow: auto;
|
||||
|
||||
.drag-move {
|
||||
min-height: 62px;
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
.list-main {
|
||||
// 列表动画
|
||||
.list-enter-active {
|
||||
transition: all 0.5s;
|
||||
}
|
||||
|
||||
.list-leave-active {
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.list-enter,
|
||||
.list-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateX(-100px);
|
||||
}
|
||||
|
||||
.list-enter {
|
||||
height: 30px;
|
||||
}
|
||||
.list-leave-active {
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.list-enter,
|
||||
.list-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateX(-100px);
|
||||
}
|
||||
|
||||
.list-enter {
|
||||
height: 30px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<!--
|
||||
* @Description: 右侧属性配置面板
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent } from 'vue'
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue'
|
||||
import { TabPane, Tabs } from 'ant-design-vue'
|
||||
import FormProps from '../components/FormProps.vue'
|
||||
import FormItemProps from '../components/FormItemProps.vue'
|
||||
|
@ -15,25 +15,11 @@ type ChangeTabKey = 1 | 2
|
|||
export interface IPropsPanel {
|
||||
changeTab: (key: ChangeTabKey) => void
|
||||
}
|
||||
export default defineComponent({
|
||||
name: 'PropsPanel',
|
||||
components: {
|
||||
FormProps,
|
||||
FormItemProps,
|
||||
ComponentProps,
|
||||
ComponentColumnProps,
|
||||
Tabs,
|
||||
TabPane,
|
||||
},
|
||||
setup() {
|
||||
const { formConfig } = useFormDesignState()
|
||||
const slotProps = computed(() => {
|
||||
return customComponents.find(
|
||||
item => item.component === formConfig.value.currentItem?.component,
|
||||
)
|
||||
})
|
||||
return { formConfig, customComponents, slotProps }
|
||||
},
|
||||
const { formConfig } = useFormDesignState()
|
||||
const slotProps = computed(() => {
|
||||
return customComponents.find(
|
||||
item => item.component === formConfig.value.currentItem?.component,
|
||||
)
|
||||
})
|
||||
</script>
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<!--
|
||||
* @Description: 工具栏
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { defineComponent, inject, reactive, toRefs } from 'vue'
|
||||
<script lang="ts" setup>
|
||||
import { inject, reactive } from 'vue'
|
||||
import type { UseRefHistoryReturn } from '@vueuse/core'
|
||||
import { Divider, Tooltip } from 'ant-design-vue'
|
||||
import type { IFormConfig } from '../../../typings/v-form-component'
|
||||
|
@ -15,62 +15,51 @@ interface IToolbarsConfig {
|
|||
event: string
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
name: 'OperatingArea',
|
||||
components: {
|
||||
Tooltip,
|
||||
Icon,
|
||||
Divider,
|
||||
},
|
||||
setup() {
|
||||
const state = reactive<{
|
||||
toolbarsConfigs: IToolbarsConfig[]
|
||||
}>({
|
||||
toolbarsConfigs: [
|
||||
{
|
||||
title: '预览-支持布局',
|
||||
type: 'preview',
|
||||
event: 'handlePreview',
|
||||
icon: 'ant-design:chrome-filled',
|
||||
},
|
||||
{
|
||||
title: '预览-不支持布局',
|
||||
type: 'preview',
|
||||
event: 'handlePreview2',
|
||||
icon: 'ant-design:chrome-filled',
|
||||
},
|
||||
{
|
||||
title: '导入JSON',
|
||||
type: 'importJson',
|
||||
event: 'handleOpenImportJsonModal',
|
||||
icon: 'ant-design:import-outlined',
|
||||
},
|
||||
{
|
||||
title: '生成JSON',
|
||||
type: 'exportJson',
|
||||
event: 'handleOpenJsonModal',
|
||||
icon: 'ant-design:export-outlined',
|
||||
},
|
||||
{
|
||||
title: '生成代码',
|
||||
type: 'exportCode',
|
||||
event: 'handleOpenCodeModal',
|
||||
icon: 'ant-design:code-filled',
|
||||
},
|
||||
{
|
||||
title: '清空',
|
||||
type: 'reset',
|
||||
event: 'handleClearFormItems',
|
||||
icon: 'ant-design:clear-outlined',
|
||||
},
|
||||
],
|
||||
})
|
||||
const historyRef = inject('historyReturn') as UseRefHistoryReturn<IFormConfig, IFormConfig>
|
||||
|
||||
const { undo, redo, canUndo, canRedo } = historyRef
|
||||
return { ...toRefs(state), undo, redo, canUndo, canRedo }
|
||||
},
|
||||
const state = reactive<{
|
||||
toolbarsConfigs: IToolbarsConfig[]
|
||||
}>({
|
||||
toolbarsConfigs: [
|
||||
{
|
||||
title: '预览-支持布局',
|
||||
type: 'preview',
|
||||
event: 'handlePreview',
|
||||
icon: 'ant-design:chrome-filled',
|
||||
},
|
||||
{
|
||||
title: '预览-不支持布局',
|
||||
type: 'preview',
|
||||
event: 'handlePreview2',
|
||||
icon: 'ant-design:chrome-filled',
|
||||
},
|
||||
{
|
||||
title: '导入JSON',
|
||||
type: 'importJson',
|
||||
event: 'handleOpenImportJsonModal',
|
||||
icon: 'ant-design:import-outlined',
|
||||
},
|
||||
{
|
||||
title: '生成JSON',
|
||||
type: 'exportJson',
|
||||
event: 'handleOpenJsonModal',
|
||||
icon: 'ant-design:export-outlined',
|
||||
},
|
||||
{
|
||||
title: '生成代码',
|
||||
type: 'exportCode',
|
||||
event: 'handleOpenCodeModal',
|
||||
icon: 'ant-design:code-filled',
|
||||
},
|
||||
{
|
||||
title: '清空',
|
||||
type: 'reset',
|
||||
event: 'handleClearFormItems',
|
||||
icon: 'ant-design:clear-outlined',
|
||||
},
|
||||
],
|
||||
})
|
||||
const historyRef = inject('historyReturn') as UseRefHistoryReturn<IFormConfig, IFormConfig>
|
||||
|
||||
const { undo, redo, canUndo, canRedo } = historyRef
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -78,7 +67,7 @@ export default defineComponent({
|
|||
<!-- 头部操作按钮区域 start -->
|
||||
<!-- 操作左侧区域 start -->
|
||||
<div class="left-btn-box">
|
||||
<Tooltip v-for="item in toolbarsConfigs" :key="item.icon" :title="item.title">
|
||||
<Tooltip v-for="item in state.toolbarsConfigs" :key="item.icon" :title="item.title">
|
||||
<a class="toolbar-text" @click="$emit(item.event)">
|
||||
<Icon :icon="item.icon" />
|
||||
</a>
|
||||
|
|
|
@ -70,7 +70,7 @@
|
|||
&-close {
|
||||
width: auto !important;
|
||||
font-weight: normal;
|
||||
background: rgb(255 255 255/ 0%) !important;
|
||||
background: transparent !important;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,8 +9,8 @@ const { getCalcContentWidth } = useMenuSetting()
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div :class="prefixCls" :style="{ width: getCalcContentWidth }">
|
||||
<div :class="`${prefixCls}__left`">
|
||||
<div class="fixed bottom-0 right-0 z-99 w-full flex items-center border-t-1 px-6 text-base/44" :style="{ width: getCalcContentWidth }">
|
||||
<div class="flex-1-1">
|
||||
<slot name="left" />
|
||||
</div>
|
||||
<slot />
|
||||
|
@ -24,24 +24,10 @@ const { getCalcContentWidth } = useMenuSetting()
|
|||
@prefix-cls: ~'@{namespace}-page-footer';
|
||||
|
||||
.@{prefix-cls} {
|
||||
position: fixed;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: @page-footer-z-index;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
padding: 0 24px;
|
||||
line-height: 44px;
|
||||
border-top: 1px solid var(--border-color);
|
||||
box-shadow:
|
||||
0 -6px 16px -8px rgb(0 0 0 / 8%),
|
||||
0 -9px 28px 0 rgb(0 0 0 / 5%),
|
||||
0 -12px 48px 16px rgb(0 0 0 / 3%);
|
||||
transition: width 0.2s;
|
||||
|
||||
&__left {
|
||||
flex: 1 1;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -316,7 +316,7 @@ emit('register', tableAction, formActions)
|
|||
<style lang="less">
|
||||
@prefix-cls: ~'@{namespace}-basic-table';
|
||||
|
||||
[data-theme='dark'] {
|
||||
html[data-theme='dark'] {
|
||||
.ant-table-tbody > tr:hover.ant-table-row-selected > td,
|
||||
.ant-table-tbody > tr.ant-table-row-selected td {
|
||||
background-color: #262626;
|
||||
|
|
|
@ -438,6 +438,7 @@ function updateSortOption(column: BasicColumn) {
|
|||
}
|
||||
|
||||
.ant-checkbox-group {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
min-width: 260px;
|
||||
// flex-wrap: wrap;
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
import type { ComputedRef } from 'vue'
|
||||
import { unref } from 'vue'
|
||||
import type { Key } from 'ant-design-vue/lib/table/interface'
|
||||
import type { BasicTableProps } from '../types/table'
|
||||
import { ROW_KEY } from '../const'
|
||||
import { isFunction, isString } from '@/utils/is'
|
||||
|
||||
interface Options {
|
||||
setSelectedRowKeys: (keys: string[]) => void
|
||||
getSelectRowKeys: () => string[]
|
||||
setSelectedRowKeys: (keys: Key[]) => void
|
||||
getSelectRowKeys: () => Key[]
|
||||
clearSelectedRowKeys: () => void
|
||||
emit: EmitType
|
||||
getAutoCreateKey: ComputedRef<boolean | undefined>
|
||||
|
|
|
@ -163,8 +163,8 @@ export function useTable(tableProps?: Props): [
|
|||
scrollTo: (pos: string) => {
|
||||
getTableInstance().scrollTo(pos)
|
||||
},
|
||||
setShowForm: async (show: boolean) => {
|
||||
await getTableInstance().setShowForm(show)
|
||||
setShowForm: async (flag: boolean) => {
|
||||
await getTableInstance().setShowForm(flag)
|
||||
},
|
||||
getShowForm: () => {
|
||||
return toRaw(getTableInstance().getShowForm())
|
||||
|
|
|
@ -86,7 +86,7 @@ export interface TableActionType {
|
|||
expandRows: (keys: (string | number)[]) => void
|
||||
collapseAll: () => void
|
||||
scrollTo: (pos: string) => void // pos: id | "top" | "bottom"
|
||||
getSelectRowKeys: () => string[]
|
||||
getSelectRowKeys: () => Key[]
|
||||
deleteSelectRowByKey: (key: string) => void
|
||||
setPagination: (info: Partial<PaginationProps>) => void
|
||||
setTableData: <T extends Ref<Recordable<any>[]>>(values: T[]) => void
|
||||
|
@ -108,11 +108,11 @@ export interface TableActionType {
|
|||
getCacheColumns: () => BasicColumn[]
|
||||
emit?: EmitType
|
||||
updateTableData: (index: number, key: string, value: any) => Recordable
|
||||
setShowPagination: (show: boolean) => Promise<void>
|
||||
setShowPagination: (show: boolean) => void
|
||||
getShowPagination: () => boolean
|
||||
setCacheColumnsByField?: (dataIndex: string | undefined, value: BasicColumn) => void
|
||||
setCacheColumns?: (columns: BasicColumn[]) => void
|
||||
setShowForm: (show: boolean) => Promise<void>
|
||||
setShowForm: (flag: boolean) => void
|
||||
getShowForm: () => boolean
|
||||
}
|
||||
|
||||
|
@ -403,6 +403,7 @@ export interface BasicTableProps<T = any> {
|
|||
|
||||
export type CellFormat = string | ((text: string, record: Recordable, index: number) => string | number) | Map<string | number, any>
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-expect-error
|
||||
export interface BasicColumn extends ColumnProps<Recordable> {
|
||||
children?: BasicColumn[]
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
@import "transition/index.less";
|
||||
@import "var/index.less";
|
||||
@import "public.less";
|
||||
// @import "ant/index.less";
|
||||
@import "./theme.less";
|
||||
@import "./entry.css";
|
||||
|
||||
|
|
|
@ -11,7 +11,6 @@ import { openWindow } from '@/utils'
|
|||
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import { useRootSetting } from '@/hooks/setting/useRootSetting'
|
||||
import { useDesign } from '@/hooks/web/useDesign'
|
||||
|
||||
defineOptions({ name: 'LayoutFooter' })
|
||||
|
||||
|
@ -22,7 +21,6 @@ const Footer = Layout.Footer
|
|||
const { t } = useI18n()
|
||||
const { getShowFooter } = useRootSetting()
|
||||
const { currentRoute } = useRouter()
|
||||
const { prefixCls } = useDesign('layout-footer')
|
||||
|
||||
const footerRef = ref<ComponentRef>(null)
|
||||
const { setFooterHeight } = useLayoutHeight()
|
||||
|
@ -40,43 +38,15 @@ const getShowLayoutFooter = computed(() => {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<Footer v-if="getShowLayoutFooter" ref="footerRef" :class="prefixCls">
|
||||
<div :class="`${prefixCls}__links`">
|
||||
<a @click="openWindow(SITE_URL)">外包咨询</a>
|
||||
<Footer v-if="getShowLayoutFooter" ref="footerRef" class="text-center text-[var(--normal-text)]">
|
||||
<div class="mb-2">
|
||||
<a class="text-[var(--normal-text)] hover:text-[var(--hover-text)]" @click="openWindow(SITE_URL)">外包咨询</a>
|
||||
|
||||
<GithubFilled :class="`${prefixCls}__github`" @click="openWindow(GITHUB_URL)" />
|
||||
<GithubFilled class="mx-7.5 hover:text-[var(--hover-text)]" @click="openWindow(GITHUB_URL)" />
|
||||
|
||||
<a @click="openWindow(DOC_URL)">{{ t('layout.footer.onlineDocument') }}</a>
|
||||
<a class="text-[var(--normal-text)] hover:text-[var(--hover-text)]" @click="openWindow(DOC_URL)">{{
|
||||
t('layout.footer.onlineDocument') }}</a>
|
||||
</div>
|
||||
<div>Copyright ©2023 {{ SITE_TITLE }}</div>
|
||||
</Footer>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@prefix-cls: ~'@{namespace}-layout-footer';
|
||||
|
||||
.@{prefix-cls} {
|
||||
color: var(--normal-text);
|
||||
text-align: center;
|
||||
|
||||
&__links {
|
||||
margin-bottom: 8px;
|
||||
|
||||
a {
|
||||
color: var(--normal-text);
|
||||
|
||||
&:hover {
|
||||
color: var(--hover-text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__github {
|
||||
margin: 0 30px;
|
||||
|
||||
&:hover {
|
||||
color: var(--hover-text);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
<script lang="ts" setup>
|
||||
import { computed } from 'vue'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import { useDesign } from '@/hooks/web/useDesign'
|
||||
import { BasicForm, useForm } from '@/components/Form'
|
||||
import { BasicModal, useModalInner } from '@/components/Modal'
|
||||
import { useUserStore } from '@/store/modules/user'
|
||||
|
@ -11,7 +10,6 @@ import headerImg from '@/assets/images/header.jpg'
|
|||
defineOptions({ name: 'LockModal' })
|
||||
|
||||
const { t } = useI18n()
|
||||
const { prefixCls } = useDesign('header-lock-modal')
|
||||
const userStore = useUserStore()
|
||||
const lockStore = useLockStore()
|
||||
|
||||
|
@ -52,18 +50,18 @@ const avatar = computed(() => {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<BasicModal :footer="null" width="25%" :title="t('layout.header.lockScreen')" v-bind="$attrs" :class="prefixCls" @register="register">
|
||||
<div :class="`${prefixCls}__entry`">
|
||||
<div :class="`${prefixCls}__header`">
|
||||
<img :src="avatar" :class="`${prefixCls}__header-img`">
|
||||
<p :class="`${prefixCls}__header-name`">
|
||||
<BasicModal :footer="null" width="25%" :title="t('layout.header.lockScreen')" v-bind="$attrs" @register="register">
|
||||
<div class="relative rounded-10 px-8 pb-8 pt-30">
|
||||
<div class="absolute left-[calc(50%-45px)] top-0 w-auto text-center">
|
||||
<img :src="avatar" class="w-18 rounded-50%">
|
||||
<p class="mt-2">
|
||||
{{ getRealName }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<BasicForm @register="registerForm" />
|
||||
|
||||
<div :class="`${prefixCls}__footer`">
|
||||
<div class="mt-4 text-center">
|
||||
<a-button type="primary" block class="mt-2" @click="handleLock">
|
||||
{{ t('layout.header.lockScreenBtn') }}
|
||||
</a-button>
|
||||
|
@ -71,38 +69,3 @@ const avatar = computed(() => {
|
|||
</div>
|
||||
</BasicModal>
|
||||
</template>
|
||||
|
||||
<style lang="less">
|
||||
@prefix-cls: ~'@{namespace}-header-lock-modal';
|
||||
|
||||
.@{prefix-cls} {
|
||||
&__entry {
|
||||
position: relative;
|
||||
//height: 240px;
|
||||
padding: 130px 30px 30px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
&__header {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: calc(50% - 45px);
|
||||
width: auto;
|
||||
text-align: center;
|
||||
|
||||
&-img {
|
||||
width: 70px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
&-name {
|
||||
margin-top: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
&__footer {
|
||||
margin-top: 16px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
import { computed, ref, unref, watch } from 'vue'
|
||||
import { Avatar, List, Tag, Typography } from 'ant-design-vue'
|
||||
import type { ListItem } from './data'
|
||||
import { useDesign } from '@/hooks/web/useDesign'
|
||||
import { isNumber } from '@/utils/is'
|
||||
|
||||
const props = defineProps({
|
||||
|
@ -31,7 +30,6 @@ const props = defineProps({
|
|||
},
|
||||
})
|
||||
const emit = defineEmits(['update:currentPage'])
|
||||
const { prefixCls } = useDesign('header-notify-list')
|
||||
const current = ref(props.currentPage || 1)
|
||||
const getData = computed(() => {
|
||||
const { pageSize, list } = props
|
||||
|
@ -72,12 +70,12 @@ function handleTitleClick(item: ListItem) {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<List :class="prefixCls" bordered :pagination="getPagination">
|
||||
<List class="display-none" bordered :pagination="getPagination">
|
||||
<template v-for="item in getData" :key="item.id">
|
||||
<List.Item class="list-item">
|
||||
<List.Item class="cursor-pointer overflow-hidden p-1.5 transition-all delay-300">
|
||||
<List.Item.Meta>
|
||||
<template #title>
|
||||
<div class="title">
|
||||
<div class="mb-2 font-normal">
|
||||
<Typography.Paragraph
|
||||
style="width: 100%; margin-bottom: 0 !important"
|
||||
:style="{ cursor: isTitleClickable ? 'pointer' : '' }"
|
||||
|
@ -86,8 +84,8 @@ function handleTitleClick(item: ListItem) {
|
|||
:content="item.title"
|
||||
@click="handleTitleClick(item)"
|
||||
/>
|
||||
<div v-if="item.extra" class="extra">
|
||||
<Tag class="tag" :color="item.color">
|
||||
<div v-if="item.extra" class="float-right mr-0 font-normal -mt-0.375">
|
||||
<Tag class="mr-0" :color="item.color">
|
||||
{{ item.extra }}
|
||||
</Tag>
|
||||
</div>
|
||||
|
@ -95,20 +93,20 @@ function handleTitleClick(item: ListItem) {
|
|||
</template>
|
||||
|
||||
<template #avatar>
|
||||
<Avatar v-if="item.avatar" class="avatar" :src="item.avatar" />
|
||||
<Avatar v-if="item.avatar" class="mt-1" :src="item.avatar" />
|
||||
<span v-else> {{ item.avatar }}</span>
|
||||
</template>
|
||||
|
||||
<template #description>
|
||||
<div>
|
||||
<div v-if="item.description" class="description">
|
||||
<div v-if="item.description" class="text-xs/18">
|
||||
<Typography.Paragraph
|
||||
style="width: 100%; margin-bottom: 0 !important"
|
||||
:ellipsis="$props.descRows && $props.descRows > 0 ? { rows: $props.descRows, tooltip: !!item.description } : false"
|
||||
:content="item.description"
|
||||
/>
|
||||
</div>
|
||||
<div class="datetime">
|
||||
<div class="mt-1 text-xs/18">
|
||||
{{ item.datetime }}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -118,55 +116,3 @@ function handleTitleClick(item: ListItem) {
|
|||
</template>
|
||||
</List>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@prefix-cls: ~'@{namespace}-header-notify-list';
|
||||
|
||||
.@{prefix-cls} {
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
::v-deep(.ant-pagination-disabled) {
|
||||
display: inline-block !important;
|
||||
}
|
||||
|
||||
&-item {
|
||||
padding: 6px;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
|
||||
.title {
|
||||
margin-bottom: 8px;
|
||||
font-weight: normal;
|
||||
|
||||
.extra {
|
||||
float: right;
|
||||
margin-top: -1.5px;
|
||||
margin-right: 0;
|
||||
font-weight: normal;
|
||||
|
||||
.tag {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.avatar {
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.description {
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.datetime {
|
||||
margin-top: 4px;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -33,5 +33,3 @@ onMounted(async () => {
|
|||
</Tooltip>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="less"></style>
|
||||
|
|
|
@ -9,7 +9,6 @@ import LayoutSideBar from './sider/index.vue'
|
|||
import { useHeaderSetting } from '@/hooks/setting/useHeaderSetting'
|
||||
import { useMenuSetting } from '@/hooks/setting/useMenuSetting'
|
||||
import { useAppInject } from '@/hooks/web/useAppInject'
|
||||
import { useDesign } from '@/hooks/web/useDesign'
|
||||
import { useLockPage } from '@/hooks/web/useLockPage'
|
||||
import { createAsyncComponent } from '@/utils/factory/createAsyncComponent'
|
||||
|
||||
|
@ -18,7 +17,6 @@ defineOptions({ name: 'DefaultLayout' })
|
|||
const LayoutFeatures = createAsyncComponent(() => import('@/layouts/default/feature/index.vue'))
|
||||
const LayoutFooter = createAsyncComponent(() => import('@/layouts/default/footer/index.vue'))
|
||||
|
||||
const { prefixCls } = useDesign('default-layout')
|
||||
const { getIsMobile } = useAppInject()
|
||||
const { getShowFullHeaderRef } = useHeaderSetting()
|
||||
const { getShowSidebar, getIsMixSidebar, getShowMenu } = useMenuSetting()
|
||||
|
@ -36,12 +34,12 @@ const layoutClass = computed(() => {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<Layout :class="prefixCls" v-bind="lockEvents">
|
||||
<Layout class="min-h-full w-full flex flex-col" v-bind="lockEvents">
|
||||
<LayoutFeatures />
|
||||
<LayoutHeader v-if="getShowFullHeaderRef" fixed />
|
||||
<Layout :class="[layoutClass]">
|
||||
<LayoutSideBar v-if="getShowSidebar || getIsMobile" />
|
||||
<Layout :class="`${prefixCls}-main`">
|
||||
<Layout class="ml-0.25 w-full">
|
||||
<LayoutMultipleHeader />
|
||||
<LayoutContent />
|
||||
<LayoutFooter />
|
||||
|
@ -49,19 +47,3 @@ const layoutClass = computed(() => {
|
|||
</Layout>
|
||||
</Layout>
|
||||
</template>
|
||||
|
||||
<style lang="less">
|
||||
@prefix-cls: ~'@{namespace}-default-layout';
|
||||
|
||||
.@{prefix-cls} {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
min-height: 100%;
|
||||
|
||||
&-main {
|
||||
width: 100%;
|
||||
margin-left: 1px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
import { InputNumber } from 'ant-design-vue'
|
||||
import { baseHandler } from '../handler'
|
||||
import type { HandlerEnum } from '../enum'
|
||||
import { useDesign } from '@/hooks/web/useDesign'
|
||||
|
||||
defineOptions({ name: 'InputNumberItem' })
|
||||
|
||||
|
@ -14,7 +13,6 @@ const props = defineProps({
|
|||
type: String,
|
||||
},
|
||||
})
|
||||
const { prefixCls } = useDesign('setting-input-number-item')
|
||||
|
||||
function handleChange(e) {
|
||||
props.event && baseHandler(props.event, e)
|
||||
|
@ -22,22 +20,8 @@ function handleChange(e) {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div :class="prefixCls">
|
||||
<div class="my-4 flex justify-between">
|
||||
<span> {{ title }}</span>
|
||||
<InputNumber v-bind="$attrs" :class="`${prefixCls}-input-number`" @change="handleChange" />
|
||||
<InputNumber v-bind="$attrs" class="max-w-32 w-30" @change="handleChange" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@prefix-cls: ~'@{namespace}-setting-input-number-item';
|
||||
|
||||
.@{prefix-cls} {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin: 16px 0;
|
||||
|
||||
&-input-number {
|
||||
width: 126px !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -4,7 +4,6 @@ import { computed } from 'vue'
|
|||
import { Select } from 'ant-design-vue'
|
||||
import { baseHandler } from '../handler'
|
||||
import type { HandlerEnum } from '../enum'
|
||||
import { useDesign } from '@/hooks/web/useDesign'
|
||||
|
||||
defineOptions({ name: 'SelectItem' })
|
||||
|
||||
|
@ -29,33 +28,19 @@ const props = defineProps({
|
|||
default: () => [],
|
||||
},
|
||||
})
|
||||
const { prefixCls } = useDesign('setting-select-item')
|
||||
const getBindValue = computed(() => {
|
||||
return props.def ? { value: props.def, defaultValue: props.initValue || props.def } : {}
|
||||
})
|
||||
|
||||
function handleChange(e: ChangeEvent) {
|
||||
function handleChange(e) {
|
||||
props.event && baseHandler(props.event, e)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div :class="prefixCls">
|
||||
<div class="my-4 flex justify-between">
|
||||
<span> {{ title }}</span>
|
||||
<Select v-bind="getBindValue" :class="`${prefixCls}-select`" :disabled="disabled" :options="options" @change="handleChange as any" />
|
||||
<Select v-bind="getBindValue" class="max-w-32 w-30" :disabled="disabled" :options="options" @change="handleChange" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@prefix-cls: ~'@{namespace}-setting-select-item';
|
||||
|
||||
.@{prefix-cls} {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin: 16px 0;
|
||||
|
||||
&-select {
|
||||
width: 126px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -8,7 +8,6 @@ import { usePermissionStore } from '@/store/modules/permission'
|
|||
import { useMultipleTabStore } from '@/store/modules/multipleTab'
|
||||
import { useUserStore } from '@/store/modules/user'
|
||||
|
||||
import { useDesign } from '@/hooks/web/useDesign'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import { useMessage } from '@/hooks/web/useMessage'
|
||||
import { useCopyToClipboard } from '@/hooks/web/useCopyToClipboard'
|
||||
|
@ -22,7 +21,6 @@ import { updateSidebarBgColor } from '@/logics/theme/updateBackground'
|
|||
defineOptions({ name: 'SettingFooter' })
|
||||
|
||||
const permissionStore = usePermissionStore()
|
||||
const { prefixCls } = useDesign('setting-footer')
|
||||
const { t } = useI18n()
|
||||
const { createSuccessModal, createMessage } = useMessage()
|
||||
const tabStore = useMultipleTabStore()
|
||||
|
@ -63,7 +61,7 @@ function handleClearAndRedo() {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div :class="prefixCls">
|
||||
<div class="flex flex-col items-center">
|
||||
<a-button type="primary" block @click="handleCopy">
|
||||
<CopyOutlined class="mr-2" />
|
||||
{{ t('layout.setting.copyBtn') }}
|
||||
|
@ -80,13 +78,3 @@ function handleClearAndRedo() {
|
|||
</a-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@prefix-cls: ~'@{namespace}-setting-footer';
|
||||
|
||||
.@{prefix-cls} {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -4,7 +4,6 @@ import { computed } from 'vue'
|
|||
import { Switch } from 'ant-design-vue'
|
||||
import { baseHandler } from '../handler'
|
||||
import type { HandlerEnum } from '../enum'
|
||||
import { useDesign } from '@/hooks/web/useDesign'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
|
||||
defineOptions({ name: 'SwitchItem' })
|
||||
|
@ -23,7 +22,6 @@ const props = defineProps({
|
|||
type: Boolean,
|
||||
},
|
||||
})
|
||||
const { prefixCls } = useDesign('setting-switch-item')
|
||||
const { t } = useI18n()
|
||||
|
||||
const getBindValue = computed(() => {
|
||||
|
@ -35,7 +33,7 @@ function handleChange(e) {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div :class="prefixCls">
|
||||
<div class="my-4 flex justify-between">
|
||||
<span> {{ title }}</span>
|
||||
<Switch
|
||||
v-bind="getBindValue"
|
||||
|
@ -46,13 +44,3 @@ function handleChange(e) {
|
|||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@prefix-cls: ~'@{namespace}-setting-switch-item';
|
||||
|
||||
.@{prefix-cls} {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin: 16px 0;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
<script lang="ts">
|
||||
<script lang="ts" setup>
|
||||
import type { CSSProperties } from 'vue'
|
||||
import { computed, defineComponent, onMounted, ref, unref, watch } from 'vue'
|
||||
import { computed, onMounted, ref, unref, watch } from 'vue'
|
||||
import type { RouteLocationNormalized } from 'vue-router'
|
||||
import { onClickOutside } from '@vueuse/core'
|
||||
import LayoutTrigger from '../trigger/index.vue'
|
||||
import { useDragLine } from './useLayoutSider'
|
||||
import type { Menu } from '@/router/types'
|
||||
|
@ -16,257 +17,220 @@ import { useDesign } from '@/hooks/web/useDesign'
|
|||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import { useGo } from '@/hooks/web/usePage'
|
||||
import { SIDE_BAR_MINI_WIDTH, SIDE_BAR_SHOW_TIT_MINI_WIDTH } from '@/enums/appEnum'
|
||||
import clickOutside from '@/directives/clickOutside'
|
||||
import { getChildrenMenus, getCurrentParentPath, getShallowMenus } from '@/router/menus'
|
||||
import { listenerRouteChange } from '@/logics/mitt/routeChange'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'LayoutMixSider',
|
||||
components: {
|
||||
ScrollContainer,
|
||||
AppLogo,
|
||||
SimpleMenu,
|
||||
Icon,
|
||||
LayoutTrigger,
|
||||
SimpleMenuTag,
|
||||
const wrap = ref(null)
|
||||
const menuModules = ref<Menu[]>([])
|
||||
const activePath = ref('')
|
||||
const childrenMenus = ref<Menu[]>([])
|
||||
const openMenu = ref(false)
|
||||
const dragBarRef = ref<ElRef>(null)
|
||||
const sideRef = ref<ElRef>(null)
|
||||
const currentRoute = ref<Nullable<RouteLocationNormalized>>(null)
|
||||
|
||||
const { prefixCls } = useDesign('layout-mix-sider')
|
||||
const go = useGo()
|
||||
const { t } = useI18n()
|
||||
const {
|
||||
getMenuWidth,
|
||||
getCanDrag,
|
||||
getCloseMixSidebarOnChange,
|
||||
getMenuTheme,
|
||||
getMixSideTrigger,
|
||||
getRealWidth,
|
||||
getMixSideFixed,
|
||||
mixSideHasChildren,
|
||||
setMenuSetting,
|
||||
getIsMixSidebar,
|
||||
getCollapsed,
|
||||
} = useMenuSetting()
|
||||
|
||||
const { title } = useGlobSetting()
|
||||
const permissionStore = usePermissionStore()
|
||||
|
||||
useDragLine(sideRef, dragBarRef, true)
|
||||
|
||||
const getMenuStyle = computed((): CSSProperties => {
|
||||
return {
|
||||
width: unref(openMenu) ? `${unref(getMenuWidth)}px` : 0,
|
||||
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
||||
left: `${unref(getMixSideWidth)}px`,
|
||||
}
|
||||
})
|
||||
|
||||
const getIsFixed = computed(() => {
|
||||
// eslint-disable-next-line vue/no-side-effects-in-computed-properties
|
||||
mixSideHasChildren.value = unref(childrenMenus).length > 0
|
||||
const isFixed = unref(getMixSideFixed) && unref(mixSideHasChildren)
|
||||
if (isFixed)
|
||||
// eslint-disable-next-line vue/no-side-effects-in-computed-properties
|
||||
openMenu.value = true
|
||||
|
||||
return isFixed
|
||||
})
|
||||
|
||||
const getMixSideWidth = computed(() => {
|
||||
return unref(getCollapsed) ? SIDE_BAR_MINI_WIDTH : SIDE_BAR_SHOW_TIT_MINI_WIDTH
|
||||
})
|
||||
|
||||
const getDomStyle = computed((): CSSProperties => {
|
||||
const fixedWidth = unref(getIsFixed) ? unref(getRealWidth) : 0
|
||||
const width = `${unref(getMixSideWidth) + fixedWidth}px`
|
||||
return getWrapCommonStyle(width)
|
||||
})
|
||||
|
||||
const getWrapStyle = computed((): CSSProperties => {
|
||||
const width = `${unref(getMixSideWidth)}px`
|
||||
return getWrapCommonStyle(width)
|
||||
})
|
||||
|
||||
const getMenuEvents = computed(() => {
|
||||
return !unref(getMixSideFixed)
|
||||
? {
|
||||
onMouseleave: () => {
|
||||
setActive(true)
|
||||
closeMenu()
|
||||
},
|
||||
}
|
||||
: {}
|
||||
})
|
||||
|
||||
const getShowDragBar = computed(() => unref(getCanDrag))
|
||||
|
||||
onMounted(async () => {
|
||||
menuModules.value = await getShallowMenus()
|
||||
})
|
||||
|
||||
// Menu changes
|
||||
watch(
|
||||
[() => permissionStore.getLastBuildMenuTime, () => permissionStore.getBackMenuList],
|
||||
async () => {
|
||||
menuModules.value = await getShallowMenus()
|
||||
},
|
||||
directives: {
|
||||
clickOutside,
|
||||
{
|
||||
immediate: true,
|
||||
},
|
||||
setup() {
|
||||
const menuModules = ref<Menu[]>([])
|
||||
const activePath = ref('')
|
||||
const childrenMenus = ref<Menu[]>([])
|
||||
const openMenu = ref(false)
|
||||
const dragBarRef = ref<ElRef>(null)
|
||||
const sideRef = ref<ElRef>(null)
|
||||
const currentRoute = ref<Nullable<RouteLocationNormalized>>(null)
|
||||
)
|
||||
|
||||
const { prefixCls } = useDesign('layout-mix-sider')
|
||||
const go = useGo()
|
||||
const { t } = useI18n()
|
||||
const {
|
||||
getMenuWidth,
|
||||
getCanDrag,
|
||||
getCloseMixSidebarOnChange,
|
||||
getMenuTheme,
|
||||
getMixSideTrigger,
|
||||
getRealWidth,
|
||||
getMixSideFixed,
|
||||
mixSideHasChildren,
|
||||
setMenuSetting,
|
||||
getIsMixSidebar,
|
||||
getCollapsed,
|
||||
} = useMenuSetting()
|
||||
listenerRouteChange((route) => {
|
||||
currentRoute.value = route
|
||||
setActive(true)
|
||||
if (unref(getCloseMixSidebarOnChange))
|
||||
closeMenu()
|
||||
})
|
||||
|
||||
const { title } = useGlobSetting()
|
||||
const permissionStore = usePermissionStore()
|
||||
function getWrapCommonStyle(width: string): CSSProperties {
|
||||
return {
|
||||
width,
|
||||
maxWidth: width,
|
||||
minWidth: width,
|
||||
flex: `0 0 ${width}`,
|
||||
}
|
||||
}
|
||||
|
||||
useDragLine(sideRef, dragBarRef, true)
|
||||
|
||||
const getMenuStyle = computed((): CSSProperties => {
|
||||
return {
|
||||
width: unref(openMenu) ? `${unref(getMenuWidth)}px` : 0,
|
||||
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
||||
left: `${unref(getMixSideWidth)}px`,
|
||||
}
|
||||
})
|
||||
|
||||
const getIsFixed = computed(() => {
|
||||
// eslint-disable-next-line vue/no-side-effects-in-computed-properties
|
||||
mixSideHasChildren.value = unref(childrenMenus).length > 0
|
||||
const isFixed = unref(getMixSideFixed) && unref(mixSideHasChildren)
|
||||
if (isFixed)
|
||||
// eslint-disable-next-line vue/no-side-effects-in-computed-properties
|
||||
// Process module menu click
|
||||
async function handleModuleClick(path: string, hover = false) {
|
||||
const children = await getChildrenMenus(path)
|
||||
if (unref(activePath) === path) {
|
||||
if (!hover) {
|
||||
if (!unref(openMenu))
|
||||
openMenu.value = true
|
||||
|
||||
return isFixed
|
||||
})
|
||||
|
||||
const getMixSideWidth = computed(() => {
|
||||
return unref(getCollapsed) ? SIDE_BAR_MINI_WIDTH : SIDE_BAR_SHOW_TIT_MINI_WIDTH
|
||||
})
|
||||
|
||||
const getDomStyle = computed((): CSSProperties => {
|
||||
const fixedWidth = unref(getIsFixed) ? unref(getRealWidth) : 0
|
||||
const width = `${unref(getMixSideWidth) + fixedWidth}px`
|
||||
return getWrapCommonStyle(width)
|
||||
})
|
||||
|
||||
const getWrapStyle = computed((): CSSProperties => {
|
||||
const width = `${unref(getMixSideWidth)}px`
|
||||
return getWrapCommonStyle(width)
|
||||
})
|
||||
|
||||
const getMenuEvents = computed(() => {
|
||||
return !unref(getMixSideFixed)
|
||||
? {
|
||||
onMouseleave: () => {
|
||||
setActive(true)
|
||||
closeMenu()
|
||||
},
|
||||
}
|
||||
: {}
|
||||
})
|
||||
|
||||
const getShowDragBar = computed(() => unref(getCanDrag))
|
||||
|
||||
onMounted(async () => {
|
||||
menuModules.value = await getShallowMenus()
|
||||
})
|
||||
|
||||
// Menu changes
|
||||
watch(
|
||||
[() => permissionStore.getLastBuildMenuTime, () => permissionStore.getBackMenuList],
|
||||
async () => {
|
||||
menuModules.value = await getShallowMenus()
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
},
|
||||
)
|
||||
|
||||
listenerRouteChange((route) => {
|
||||
currentRoute.value = route
|
||||
setActive(true)
|
||||
if (unref(getCloseMixSidebarOnChange))
|
||||
else
|
||||
closeMenu()
|
||||
})
|
||||
|
||||
function getWrapCommonStyle(width: string): CSSProperties {
|
||||
return {
|
||||
width,
|
||||
maxWidth: width,
|
||||
minWidth: width,
|
||||
flex: `0 0 ${width}`,
|
||||
}
|
||||
}
|
||||
|
||||
// Process module menu click
|
||||
async function handleModuleClick(path: string, hover = false) {
|
||||
const children = await getChildrenMenus(path)
|
||||
if (unref(activePath) === path) {
|
||||
if (!hover) {
|
||||
if (!unref(openMenu))
|
||||
openMenu.value = true
|
||||
else
|
||||
closeMenu()
|
||||
}
|
||||
else {
|
||||
if (!unref(openMenu))
|
||||
openMenu.value = true
|
||||
}
|
||||
if (!unref(openMenu))
|
||||
setActive()
|
||||
}
|
||||
else {
|
||||
else {
|
||||
if (!unref(openMenu))
|
||||
openMenu.value = true
|
||||
activePath.value = path
|
||||
}
|
||||
|
||||
if (!children || children.length === 0) {
|
||||
if (!hover)
|
||||
go(path)
|
||||
childrenMenus.value = []
|
||||
closeMenu()
|
||||
return
|
||||
}
|
||||
childrenMenus.value = children
|
||||
}
|
||||
if (!unref(openMenu))
|
||||
setActive()
|
||||
}
|
||||
else {
|
||||
openMenu.value = true
|
||||
activePath.value = path
|
||||
}
|
||||
|
||||
// Set the currently active menu and submenu
|
||||
async function setActive(setChildren = false) {
|
||||
const path = currentRoute.value?.path
|
||||
if (!path)
|
||||
return
|
||||
activePath.value = await getCurrentParentPath(path)
|
||||
// hanldeModuleClick(parentPath);
|
||||
if (unref(getIsMixSidebar)) {
|
||||
const activeMenu = unref(menuModules).find(item => item.path === unref(activePath))
|
||||
const p = activeMenu?.path
|
||||
if (p) {
|
||||
const children = await getChildrenMenus(p)
|
||||
if (setChildren) {
|
||||
childrenMenus.value = children
|
||||
|
||||
if (unref(getMixSideFixed))
|
||||
openMenu.value = children.length > 0
|
||||
}
|
||||
if (children.length === 0)
|
||||
childrenMenus.value = []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handleMenuClick(path: string) {
|
||||
if (!children || children.length === 0) {
|
||||
if (!hover)
|
||||
go(path)
|
||||
}
|
||||
childrenMenus.value = []
|
||||
closeMenu()
|
||||
return
|
||||
}
|
||||
childrenMenus.value = children
|
||||
}
|
||||
|
||||
function handleClickOutside() {
|
||||
setActive(true)
|
||||
closeMenu()
|
||||
}
|
||||
// Set the currently active menu and submenu
|
||||
async function setActive(setChildren = false) {
|
||||
const path = currentRoute.value?.path
|
||||
if (!path)
|
||||
return
|
||||
activePath.value = await getCurrentParentPath(path)
|
||||
// hanldeModuleClick(parentPath);
|
||||
if (unref(getIsMixSidebar)) {
|
||||
const activeMenu = unref(menuModules).find(item => item.path === unref(activePath))
|
||||
const p = activeMenu?.path
|
||||
if (p) {
|
||||
const children = await getChildrenMenus(p)
|
||||
if (setChildren) {
|
||||
childrenMenus.value = children
|
||||
|
||||
function getItemEvents(item: Menu) {
|
||||
if (unref(getMixSideTrigger) === 'hover') {
|
||||
return {
|
||||
onMouseenter: () => handleModuleClick(item.path, true),
|
||||
onClick: async () => {
|
||||
const children = await getChildrenMenus(item.path)
|
||||
if (item.path && (!children || children.length === 0))
|
||||
go(item.path)
|
||||
},
|
||||
}
|
||||
}
|
||||
return {
|
||||
onClick: () => handleModuleClick(item.path),
|
||||
if (unref(getMixSideFixed))
|
||||
openMenu.value = children.length > 0
|
||||
}
|
||||
if (children.length === 0)
|
||||
childrenMenus.value = []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handleFixedMenu() {
|
||||
setMenuSetting({
|
||||
mixSideFixed: !unref(getIsFixed),
|
||||
})
|
||||
}
|
||||
function handleMenuClick(path: string) {
|
||||
go(path)
|
||||
}
|
||||
|
||||
// Close menu
|
||||
function closeMenu() {
|
||||
if (!unref(getIsFixed))
|
||||
openMenu.value = false
|
||||
}
|
||||
function handleClickOutside() {
|
||||
setActive(true)
|
||||
closeMenu()
|
||||
}
|
||||
|
||||
function getItemEvents(item: Menu) {
|
||||
if (unref(getMixSideTrigger) === 'hover') {
|
||||
return {
|
||||
t,
|
||||
prefixCls,
|
||||
menuModules,
|
||||
handleModuleClick,
|
||||
activePath,
|
||||
childrenMenus,
|
||||
getShowDragBar,
|
||||
handleMenuClick,
|
||||
getMenuStyle,
|
||||
handleClickOutside,
|
||||
sideRef,
|
||||
dragBarRef,
|
||||
title,
|
||||
openMenu,
|
||||
getMenuTheme,
|
||||
getItemEvents,
|
||||
getMenuEvents,
|
||||
getDomStyle,
|
||||
handleFixedMenu,
|
||||
getMixSideFixed,
|
||||
getWrapStyle,
|
||||
getCollapsed,
|
||||
onMouseenter: () => handleModuleClick(item.path, true),
|
||||
onClick: async () => {
|
||||
const children = await getChildrenMenus(item.path)
|
||||
if (item.path && (!children || children.length === 0))
|
||||
go(item.path)
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
return {
|
||||
onClick: () => handleModuleClick(item.path),
|
||||
}
|
||||
}
|
||||
|
||||
function handleFixedMenu() {
|
||||
setMenuSetting({
|
||||
mixSideFixed: !unref(getIsFixed),
|
||||
})
|
||||
}
|
||||
|
||||
// Close menu
|
||||
function closeMenu() {
|
||||
if (!unref(getIsFixed))
|
||||
openMenu.value = false
|
||||
}
|
||||
|
||||
onClickOutside(wrap, () => {
|
||||
handleClickOutside()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div :class="`${prefixCls}-dom`" :style="getDomStyle" />
|
||||
<div
|
||||
v-click-outside="handleClickOutside"
|
||||
ref="wrap"
|
||||
:style="getWrapStyle"
|
||||
:class="[
|
||||
prefixCls,
|
||||
|
|
|
@ -26,7 +26,7 @@ const title = computed(() => globSetting?.title ?? '')
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div :class="prefixCls" class="relative h-full w-full px-4">
|
||||
<div :class="prefixCls" class="relative h-full min-h-full w-full overflow-hidden px-4">
|
||||
<div class="absolute right-4 top-4 flex items-center">
|
||||
<AppDarkModeToggle v-if="!sessionTimeout" class="enter-x mr-2" />
|
||||
<AppLocalePicker v-if="!sessionTimeout && showLocale" class="enter-x xl:text-gray-600" :show-text="false" />
|
||||
|
@ -108,9 +108,6 @@ html[data-theme='dark'] {
|
|||
}
|
||||
|
||||
.@{prefix-cls} {
|
||||
min-height: 100%;
|
||||
overflow: hidden;
|
||||
|
||||
@media (max-width: @screen-xl) {
|
||||
background-color: #293146;
|
||||
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
<script lang="ts" setup>
|
||||
import { onBeforeUnmount, onMounted, ref } from 'vue'
|
||||
import Login from './Login.vue'
|
||||
import { useDesign } from '@/hooks/web/useDesign'
|
||||
import { useUserStore } from '@/store/modules/user'
|
||||
import { usePermissionStore } from '@/store/modules/permission'
|
||||
import { useAppStore } from '@/store/modules/app'
|
||||
import { PermissionModeEnum } from '@/enums/appEnum'
|
||||
|
||||
const { prefixCls } = useDesign('st-login')
|
||||
const userStore = useUserStore()
|
||||
const permissionStore = usePermissionStore()
|
||||
const appStore = useAppStore()
|
||||
|
@ -36,20 +34,8 @@ onBeforeUnmount(() => {
|
|||
|
||||
<template>
|
||||
<transition>
|
||||
<div :class="prefixCls">
|
||||
<div class="fixed z-9999999 h-full w-full bg-[var(--component-background)]">
|
||||
<Login session-timeout />
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@prefix-cls: ~'@{namespace}-st-login';
|
||||
|
||||
.@{prefix-cls} {
|
||||
position: fixed;
|
||||
z-index: 9999999;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: var(--component-background);
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -32,11 +32,11 @@ onMounted(async () => {
|
|||
<List.Item>
|
||||
<List.Item.Meta>
|
||||
<template #avatar>
|
||||
<Icon v-if="item.avatar" class="avatar" :icon="item.avatar" :color="item.color" />
|
||||
<Icon v-if="item.avatar" class="text-4xl" :icon="item.avatar" :color="item.color" />
|
||||
</template>
|
||||
<template #title>
|
||||
{{ item.title }}
|
||||
<a-button v-if="item.extra" type="link" size="small" class="extra">
|
||||
<a-button v-if="item.extra" type="link" size="small" class="float-right mr-7.5 mt-2.5 cursor-pointer">
|
||||
{{ item.extra }}
|
||||
</a-button>
|
||||
</template>
|
||||
|
@ -49,16 +49,3 @@ onMounted(async () => {
|
|||
</List>
|
||||
</CollapseContainer>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.avatar {
|
||||
font-size: 40px !important;
|
||||
}
|
||||
|
||||
.extra {
|
||||
float: right;
|
||||
margin-top: 10px;
|
||||
margin-right: 30px;
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -54,7 +54,7 @@ async function handleSubmit() {
|
|||
<BasicForm @register="register" />
|
||||
</Col>
|
||||
<Col :span="10">
|
||||
<div class="change-avatar">
|
||||
<div>
|
||||
<div class="mb-2">
|
||||
头像
|
||||
</div>
|
||||
|
@ -63,6 +63,7 @@ async function handleSubmit() {
|
|||
btn-text="更换头像"
|
||||
:btn-props="{ preIcon: 'ant-design:cloud-upload-outlined' }"
|
||||
width="150"
|
||||
class="mb-4 block rounded-full"
|
||||
@change="updateAvatar"
|
||||
/>
|
||||
</div>
|
||||
|
@ -73,13 +74,3 @@ async function handleSubmit() {
|
|||
</Button>
|
||||
</CollapseContainer>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.change-avatar {
|
||||
img {
|
||||
display: block;
|
||||
margin-bottom: 15px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -15,7 +15,7 @@ const ListItemMeta = List.Item.Meta
|
|||
<ListItemMeta>
|
||||
<template #title>
|
||||
{{ item.title }}
|
||||
<Switch class="extra" checked-children="开" un-checked-children="关" default-checked />
|
||||
<Switch class="float-right mr-7.5 mt-0" checked-children="开" un-checked-children="关" default-checked />
|
||||
</template>
|
||||
<template #description>
|
||||
<div>{{ item.description }}</div>
|
||||
|
@ -26,11 +26,3 @@ const ListItemMeta = List.Item.Meta
|
|||
</List>
|
||||
</CollapseContainer>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.extra {
|
||||
float: right;
|
||||
margin-top: 10px;
|
||||
margin-right: 30px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -29,7 +29,7 @@ function handleSuccess() {
|
|||
<ListItemMeta>
|
||||
<template #title>
|
||||
{{ item.title }}
|
||||
<div v-if="item.extra" class="extra">
|
||||
<div v-if="item.extra" class="float-right mr-7.5 mt-2.5 cursor-pointer font-normal text-blue-500">
|
||||
<a-button type="link" @click="handleEdit(item.title)">
|
||||
{{ item.extra }}
|
||||
</a-button>
|
||||
|
@ -45,14 +45,3 @@ function handleSuccess() {
|
|||
</CollapseContainer>
|
||||
<PasswordModal @register="registerModal" @success="handleSuccess" />
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.extra {
|
||||
float: right;
|
||||
margin-top: 10px;
|
||||
margin-right: 30px;
|
||||
font-weight: normal;
|
||||
color: #1890ff;
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -15,7 +15,7 @@ const tabBarStyle = { width: '220px' }
|
|||
|
||||
<template>
|
||||
<ScrollContainer>
|
||||
<div ref="wrapperRef" class="account-setting">
|
||||
<div ref="wrapperRef" class="m-3 rounded-1.5 bg-[var(--component-background)]">
|
||||
<Tabs tab-position="left" :tab-bar-style="tabBarStyle">
|
||||
<template v-for="item in settingList" :key="item.key">
|
||||
<TabPane :tab="item.name">
|
||||
|
@ -29,19 +29,3 @@ const tabBarStyle = { width: '220px' }
|
|||
</div>
|
||||
</ScrollContainer>
|
||||
</template>
|
||||
|
||||
<style lang="less">
|
||||
.account-setting {
|
||||
margin: 12px;
|
||||
background-color: var(--component-background);
|
||||
border-radius: 6px;
|
||||
|
||||
.base-title {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
// .ant-tabs-tab-active {
|
||||
// background-color: @item-active-bg;
|
||||
// }
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -78,7 +78,7 @@ async function submitForm(formData) {
|
|||
|
||||
<template>
|
||||
<PageWrapper>
|
||||
<div class="step-form-form">
|
||||
<div class="mx-auto my-0 mt-2.5 w-200">
|
||||
<Steps :current="current">
|
||||
<Steps.Step title="选择流程" />
|
||||
<Steps.Step title="流程提交" />
|
||||
|
@ -113,11 +113,3 @@ async function submitForm(formData) {
|
|||
</div>
|
||||
</PageWrapper>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.step-form-form {
|
||||
width: 750px;
|
||||
margin: 0 auto;
|
||||
margin-top: 10px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -73,7 +73,7 @@ onMounted(async () => {
|
|||
|
||||
<template>
|
||||
<PageWrapper>
|
||||
<div class="step-form-form">
|
||||
<div class="mx-auto my-0 mt-2.5 w-200">
|
||||
<Steps :current="current">
|
||||
<Step title="生成信息" />
|
||||
<Step title="字段信息" />
|
||||
|
@ -94,11 +94,3 @@ onMounted(async () => {
|
|||
</div>
|
||||
</PageWrapper>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.step-form-form {
|
||||
width: 750px;
|
||||
margin: 0 auto;
|
||||
margin-top: 10px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -51,46 +51,20 @@ watch(
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div class="step1">
|
||||
<div class="step1-form">
|
||||
<div>
|
||||
<div class="mx-auto my-0 w-80%">
|
||||
<BasicForm @register="register" />
|
||||
</div>
|
||||
<Divider />
|
||||
<h3>说明</h3>
|
||||
<h4>基本信息</h4>
|
||||
<h3 class="mb-3 text-base">
|
||||
说明
|
||||
</h3>
|
||||
<h4 class="mb-1 text-sm">
|
||||
基本信息
|
||||
</h4>
|
||||
<p> 配置生成的基本信息 </p>
|
||||
|
||||
<h4>生成信息</h4>
|
||||
<p> 配置生成生成的详细信息。 </p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.step1 {
|
||||
&-form {
|
||||
width: 80%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin: 0 0 12px;
|
||||
font-size: 16px;
|
||||
line-height: 32px;
|
||||
}
|
||||
|
||||
h4 {
|
||||
margin: 0 0 4px;
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.pay-select {
|
||||
width: 20%;
|
||||
}
|
||||
|
||||
.pay-input {
|
||||
width: 70%;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -39,11 +39,11 @@ function handleEdit(record: EditRecordRow) {
|
|||
|
||||
<template>
|
||||
<div class="step2">
|
||||
<div class="step2-table">
|
||||
<div class="mx-auto my-0 w-full">
|
||||
<BasicTable :data-source="columnsInfo" @register="registerTable" @row-click="handleEdit" />
|
||||
</div>
|
||||
<Divider />
|
||||
<div class="step2-button">
|
||||
<div class="flex justify-center">
|
||||
<a-button @click="customResetFunc">
|
||||
上一步
|
||||
</a-button>
|
||||
|
@ -51,35 +51,12 @@ function handleEdit(record: EditRecordRow) {
|
|||
提交
|
||||
</a-button>
|
||||
</div>
|
||||
<h3>说明</h3>
|
||||
<h4>配置字段</h4>
|
||||
<h3 class="mb-3 text-base">
|
||||
说明
|
||||
</h3>
|
||||
<h4 class="mb-1 text-sm">
|
||||
配置字段
|
||||
</h4>
|
||||
<p> 配置表的字段类型,增删改查,字典等 </p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.step2 {
|
||||
&-table {
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
&-button {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin: 0 0 12px;
|
||||
font-size: 16px;
|
||||
line-height: 32px;
|
||||
}
|
||||
|
||||
h4 {
|
||||
margin: 0 0 4px;
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -36,7 +36,7 @@ function handleGoList() {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div class="result-success m-5">
|
||||
<div class="m-5 bg-white px-8 py-12 dark:bg-dark">
|
||||
<Result status="success" title="代码生成成功" sub-title="可点击下方按钮预览、下载,或返回列表页。">
|
||||
<template #extra>
|
||||
<a-button key="console" type="primary" @click="handleGoList">
|
||||
|
@ -53,15 +53,3 @@ function handleGoList() {
|
|||
<PreviewModal @register="registerPreviewModal" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.result-success {
|
||||
padding: 48px 32px;
|
||||
background-color: var(--component-background);
|
||||
|
||||
&__content {
|
||||
padding: 24px 40px;
|
||||
background-color: @background-color-light;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
Loading…
Reference in New Issue