feat(I18n): Add Ii8n
feat(LocaleDropdown): Add LocaleDropdown Component feat(store): Add localeStore
This commit is contained in:
parent
45d657d44c
commit
3810b8c3b2
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
"0 debug pnpm:scope": {
|
||||||
|
"selected": 1
|
||||||
|
},
|
||||||
|
"1 error pnpm": {
|
||||||
|
"errno": 1,
|
||||||
|
"code": "ELIFECYCLE",
|
||||||
|
"pkgid": "butterfly-admin@3.0.0",
|
||||||
|
"stage": "clean",
|
||||||
|
"script": "npx rimraf docs/node_modules && npx rimraf node_modules",
|
||||||
|
"pkgname": "butterfly-admin",
|
||||||
|
"err": {
|
||||||
|
"name": "pnpm",
|
||||||
|
"message": "butterfly-admin@3.0.0 clean: `npx rimraf docs/node_modules && npx rimraf node_modules`\nExit status 1",
|
||||||
|
"code": "ELIFECYCLE",
|
||||||
|
"stack": "pnpm: butterfly-admin@3.0.0 clean: `npx rimraf docs/node_modules && npx rimraf node_modules`\nExit status 1\n at EventEmitter.<anonymous> (C:\\Users\\Saber\\AppData\\Roaming\\npm\\pnpm-global\\5\\node_modules\\.pnpm\\registry.npmmirror.com+pnpm@6.24.4\\node_modules\\pnpm\\dist\\pnpm.cjs:103873:20)\n at EventEmitter.emit (node:events:365:28)\n at ChildProcess.<anonymous> (C:\\Users\\Saber\\AppData\\Roaming\\npm\\pnpm-global\\5\\node_modules\\.pnpm\\registry.npmmirror.com+pnpm@6.24.4\\node_modules\\pnpm\\dist\\pnpm.cjs:91802:18)\n at ChildProcess.emit (node:events:365:28)\n at maybeClose (node:internal/child_process:1067:16)\n at Process.ChildProcess._handle.onexit (node:internal/child_process:301:5)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
18
package.json
18
package.json
|
@ -25,9 +25,10 @@
|
||||||
"postinstall": "husky install"
|
"postinstall": "husky install"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vueuse/core": "^7.4.1",
|
"@iconify/iconify": "^2.1.0",
|
||||||
|
"@vueuse/core": "^7.5.1",
|
||||||
"@zxcvbn-ts/core": "^1.2.0",
|
"@zxcvbn-ts/core": "^1.2.0",
|
||||||
"element-plus": "1.2.0-beta.6",
|
"element-plus": "1.3.0-beta.1",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"pinia": "^2.0.9",
|
"pinia": "^2.0.9",
|
||||||
"vue": "3.2.26",
|
"vue": "3.2.26",
|
||||||
|
@ -38,8 +39,9 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@commitlint/cli": "^16.0.1",
|
"@commitlint/cli": "^16.0.1",
|
||||||
"@commitlint/config-conventional": "^16.0.0",
|
"@commitlint/config-conventional": "^16.0.0",
|
||||||
"@iconify/json": "^1.1.448",
|
"@iconify/json": "^1.1.450",
|
||||||
"@intlify/vite-plugin-vue-i18n": "^3.2.1",
|
"@intlify/vite-plugin-vue-i18n": "^3.2.1",
|
||||||
|
"@purge-icons/generated": "^0.7.0",
|
||||||
"@types/lodash-es": "^4.17.5",
|
"@types/lodash-es": "^4.17.5",
|
||||||
"@types/node": "^17.0.5",
|
"@types/node": "^17.0.5",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.8.1",
|
"@typescript-eslint/eslint-plugin": "^5.8.1",
|
||||||
|
@ -49,7 +51,7 @@
|
||||||
"async-validator": "^4.0.7",
|
"async-validator": "^4.0.7",
|
||||||
"autoprefixer": "^10.4.1",
|
"autoprefixer": "^10.4.1",
|
||||||
"commitizen": "^4.2.4",
|
"commitizen": "^4.2.4",
|
||||||
"eslint": "^8.5.0",
|
"eslint": "^8.6.0",
|
||||||
"eslint-config-prettier": "^8.3.0",
|
"eslint-config-prettier": "^8.3.0",
|
||||||
"eslint-define-config": "^1.2.1",
|
"eslint-define-config": "^1.2.1",
|
||||||
"eslint-plugin-prettier": "^4.0.0",
|
"eslint-plugin-prettier": "^4.0.0",
|
||||||
|
@ -69,14 +71,14 @@
|
||||||
"stylelint-config-standard": "^24.0.0",
|
"stylelint-config-standard": "^24.0.0",
|
||||||
"stylelint-order": "^5.0.0",
|
"stylelint-order": "^5.0.0",
|
||||||
"typescript": "4.5.4",
|
"typescript": "4.5.4",
|
||||||
"unplugin-icons": "^0.13.0",
|
"vite": "2.7.10",
|
||||||
"vite": "2.7.9",
|
|
||||||
"vite-plugin-eslint": "^1.3.0",
|
"vite-plugin-eslint": "^1.3.0",
|
||||||
|
"vite-plugin-purge-icons": "^0.7.0",
|
||||||
"vite-plugin-style-import": "^1.4.1",
|
"vite-plugin-style-import": "^1.4.1",
|
||||||
"vite-plugin-svg-icons": "^1.0.5",
|
"vite-plugin-svg-icons": "^1.1.0",
|
||||||
"vite-plugin-windicss": "^1.6.1",
|
"vite-plugin-windicss": "^1.6.1",
|
||||||
"vue-tsc": "^0.30.1",
|
"vue-tsc": "^0.30.1",
|
||||||
"windicss": "^3.4.1",
|
"windicss": "^3.4.2",
|
||||||
"windicss-analysis": "^0.3.5"
|
"windicss-analysis": "^0.3.5"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|
1074
pnpm-lock.yaml
1074
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
20
src/App.vue
20
src/App.vue
|
@ -1,30 +1,30 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, unref } from 'vue'
|
import { computed } from 'vue'
|
||||||
import { useAppStore } from '@/store/modules/app'
|
import { useAppStore } from '@/store/modules/app'
|
||||||
|
import { useLocaleStore } from '@/store/modules/locale'
|
||||||
import { ElConfigProvider } from 'element-plus'
|
import { ElConfigProvider } from 'element-plus'
|
||||||
import { VConfigGlobal } from '@/components/ConfigGlobal'
|
import { ConfigGlobal } from '@/components/ConfigGlobal'
|
||||||
import zhCn from 'element-plus/lib/locale/lang/zh-cn'
|
|
||||||
import en from 'element-plus/lib/locale/lang/en'
|
|
||||||
import { isDark } from '@/utils/is'
|
import { isDark } from '@/utils/is'
|
||||||
|
|
||||||
const appStore = useAppStore()
|
const appStore = useAppStore()
|
||||||
|
|
||||||
|
const localeStore = useLocaleStore()
|
||||||
|
|
||||||
|
const local = computed(() => localeStore.locale)
|
||||||
|
|
||||||
function initDark() {
|
function initDark() {
|
||||||
const isDarkTheme = isDark()
|
const isDarkTheme = isDark()
|
||||||
appStore.setIsDark(isDarkTheme)
|
appStore.setIsDark(isDarkTheme)
|
||||||
}
|
}
|
||||||
initDark()
|
initDark()
|
||||||
|
|
||||||
const locale = computed(() => appStore.getLang)
|
|
||||||
const setLocale = computed(() => (unref(locale) === 'zh-cn' ? zhCn : en))
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<VConfigGlobal>
|
<ConfigGlobal>
|
||||||
<ElConfigProvider :locale="setLocale">
|
<ElConfigProvider :locale="local.elLocale">
|
||||||
<RouterView />
|
<RouterView />
|
||||||
</ElConfigProvider>
|
</ElConfigProvider>
|
||||||
</VConfigGlobal>
|
</ConfigGlobal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M115.147.062a13 13 0 0 1 4.94.945c1.55.63 2.907 1.526 4.069 2.688a13.148 13.148 0 0 1 2.761 4.069c.678 1.55 1.017 3.245 1.017 5.086v102.3c0 3.681-1.187 6.733-3.56 9.155-2.373 2.422-5.352 3.633-8.937 3.633H12.992c-3.875 0-7-1.26-9.373-3.779-2.373-2.518-3.56-5.667-3.56-9.445V12.704c0-3.39 1.163-6.345 3.488-8.863C5.872 1.32 8.972.062 12.847.062h102.3zM81.434 109.047c1.744 0 3.003-.412 3.778-1.235.775-.824 1.163-1.914 1.163-3.27 0-1.26-.388-2.325-1.163-3.197-.775-.872-2.034-1.307-3.778-1.307H72.57c.097-.194.145-.485.145-.872V27.09h9.01c1.743 0 2.954-.436 3.633-1.308.678-.872 1.017-1.938 1.017-3.197 0-1.26-.34-2.325-1.017-3.197-.679-.872-1.89-1.308-3.633-1.308H46.268c-1.743 0-2.954.436-3.632 1.308-.678.872-1.018 1.938-1.018 3.197 0 1.26.34 2.325 1.018 3.197.678.872 1.889 1.308 3.632 1.308h8.138v72.075c0 .193.024.339.073.436.048.096.072.242.072.436H46.56c-1.744 0-3.003.435-3.778 1.307-.775.872-1.163 1.938-1.163 3.197 0 1.356.388 2.446 1.163 3.27.775.823 2.034 1.235 3.778 1.235h34.875z"/></svg>
|
After Width: | Height: | Size: 1.1 KiB |
|
@ -1,3 +1,3 @@
|
||||||
import VConfigGlobal from './src/VConfigGlobal.vue'
|
import ConfigGlobal from './src/ConfigGlobal.vue'
|
||||||
|
|
||||||
export { VConfigGlobal }
|
export { ConfigGlobal }
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import VFrom from './src/VForm.vue'
|
import VFrom from './src/Form.vue'
|
||||||
|
|
||||||
export interface VFormExpose {
|
export interface VFormExpose {
|
||||||
count: number
|
count: number
|
||||||
|
|
|
@ -20,7 +20,7 @@ export default defineComponent({
|
||||||
props: {
|
props: {
|
||||||
// 生成Form的布局结构数组
|
// 生成Form的布局结构数组
|
||||||
schema: {
|
schema: {
|
||||||
type: Array as PropType<VFormSchema[]>,
|
type: Array as PropType<FormSchema[]>,
|
||||||
required: true,
|
required: true,
|
||||||
default: () => []
|
default: () => []
|
||||||
},
|
},
|
||||||
|
@ -98,7 +98,7 @@ export default defineComponent({
|
||||||
}
|
}
|
||||||
|
|
||||||
// 渲染formItem
|
// 渲染formItem
|
||||||
function renderFormItem(item: VFormSchema) {
|
function renderFormItem(item: FormSchema) {
|
||||||
// 单独给只有options属性的组件做判断
|
// 单独给只有options属性的组件做判断
|
||||||
const notRenderOptions = ['SelectV2', 'Cascader', 'Transfer']
|
const notRenderOptions = ['SelectV2', 'Cascader', 'Transfer']
|
||||||
const slotsMap: Recordable = {
|
const slotsMap: Recordable = {
|
||||||
|
@ -134,7 +134,7 @@ export default defineComponent({
|
||||||
}
|
}
|
||||||
|
|
||||||
// 渲染options
|
// 渲染options
|
||||||
function renderOptions(item: VFormSchema) {
|
function renderOptions(item: FormSchema) {
|
||||||
switch (item.component) {
|
switch (item.component) {
|
||||||
case 'Select':
|
case 'Select':
|
||||||
const { renderSelectOptions } = useRenderSelect(slots)
|
const { renderSelectOptions } = useRenderSelect(slots)
|
|
@ -18,7 +18,7 @@ import {
|
||||||
ElAutocomplete,
|
ElAutocomplete,
|
||||||
ElDivider
|
ElDivider
|
||||||
} from 'element-plus'
|
} from 'element-plus'
|
||||||
import { VInputPassword } from '@/components/InputPassword'
|
import { InputPassword } from '@/components/InputPassword'
|
||||||
|
|
||||||
const componentMap: Recordable<Component, ComponentName> = {
|
const componentMap: Recordable<Component, ComponentName> = {
|
||||||
Radio: ElRadioGroup,
|
Radio: ElRadioGroup,
|
||||||
|
@ -40,7 +40,7 @@ const componentMap: Recordable<Component, ComponentName> = {
|
||||||
TimeSelect: ElTimeSelect,
|
TimeSelect: ElTimeSelect,
|
||||||
SelectV2: ElSelectV2,
|
SelectV2: ElSelectV2,
|
||||||
RadioButton: ElRadioGroup,
|
RadioButton: ElRadioGroup,
|
||||||
InputPassword: VInputPassword
|
InputPassword: InputPassword
|
||||||
}
|
}
|
||||||
|
|
||||||
export { componentMap }
|
export { componentMap }
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { ElCheckbox, ElCheckboxButton } from 'element-plus'
|
||||||
import { defineComponent } from 'vue'
|
import { defineComponent } from 'vue'
|
||||||
|
|
||||||
export function useRenderChcekbox() {
|
export function useRenderChcekbox() {
|
||||||
function renderChcekboxOptions(item: VFormSchema) {
|
function renderChcekboxOptions(item: FormSchema) {
|
||||||
// 如果有别名,就取别名
|
// 如果有别名,就取别名
|
||||||
const labelAlias = item?.componentProps?.optionsAlias?.labelField
|
const labelAlias = item?.componentProps?.optionsAlias?.labelField
|
||||||
const valueAlias = item?.componentProps?.optionsAlias?.valueField
|
const valueAlias = item?.componentProps?.optionsAlias?.valueField
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { ElRadio, ElRadioButton } from 'element-plus'
|
||||||
import { defineComponent } from 'vue'
|
import { defineComponent } from 'vue'
|
||||||
|
|
||||||
export function useRenderRadio() {
|
export function useRenderRadio() {
|
||||||
function renderRadioOptions(item: VFormSchema) {
|
function renderRadioOptions(item: FormSchema) {
|
||||||
// 如果有别名,就取别名
|
// 如果有别名,就取别名
|
||||||
const labelAlias = item?.componentProps?.optionsAlias?.labelField
|
const labelAlias = item?.componentProps?.optionsAlias?.labelField
|
||||||
const valueAlias = item?.componentProps?.optionsAlias?.valueField
|
const valueAlias = item?.componentProps?.optionsAlias?.valueField
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { Slots } from 'vue'
|
||||||
|
|
||||||
export function useRenderSelect(slots: Slots) {
|
export function useRenderSelect(slots: Slots) {
|
||||||
// 渲染 select options
|
// 渲染 select options
|
||||||
function renderSelectOptions(item: VFormSchema) {
|
function renderSelectOptions(item: FormSchema) {
|
||||||
// 如果有别名,就取别名
|
// 如果有别名,就取别名
|
||||||
const labelAlias = item?.componentProps?.optionsAlias?.labelField
|
const labelAlias = item?.componentProps?.optionsAlias?.labelField
|
||||||
return item?.componentProps?.options?.map((option) => {
|
return item?.componentProps?.options?.map((option) => {
|
||||||
|
@ -25,7 +25,7 @@ export function useRenderSelect(slots: Slots) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 渲染 select option item
|
// 渲染 select option item
|
||||||
function renderSelectOptionItem(item: VFormSchema, option: ComponentOptions) {
|
function renderSelectOptionItem(item: FormSchema, option: ComponentOptions) {
|
||||||
// 如果有别名,就取别名
|
// 如果有别名,就取别名
|
||||||
const labelAlias = item?.componentProps?.optionsAlias?.labelField
|
const labelAlias = item?.componentProps?.optionsAlias?.labelField
|
||||||
const valueAlias = item?.componentProps?.optionsAlias?.valueField
|
const valueAlias = item?.componentProps?.optionsAlias?.valueField
|
||||||
|
|
|
@ -16,7 +16,7 @@ interface PlaceholderMoel {
|
||||||
* @returns 返回提示信息对象
|
* @returns 返回提示信息对象
|
||||||
* @description 用于自动设置placeholder
|
* @description 用于自动设置placeholder
|
||||||
*/
|
*/
|
||||||
export function setTextPlaceholder(schema: VFormSchema): PlaceholderMoel {
|
export function setTextPlaceholder(schema: FormSchema): PlaceholderMoel {
|
||||||
const textMap = ['Input', 'Autocomplete', 'InputNumber', 'InputPassword']
|
const textMap = ['Input', 'Autocomplete', 'InputNumber', 'InputPassword']
|
||||||
const selectMap = ['Select', 'TimePicker', 'DatePicker', 'TimeSelect', 'TimeSelect']
|
const selectMap = ['Select', 'TimePicker', 'DatePicker', 'TimeSelect', 'TimeSelect']
|
||||||
if (textMap.includes(schema?.component as string)) {
|
if (textMap.includes(schema?.component as string)) {
|
||||||
|
@ -74,7 +74,7 @@ export function setGridProp(col: ColProps = {}): ColProps {
|
||||||
* @param item 传入的组件属性
|
* @param item 传入的组件属性
|
||||||
* @returns 默认添加 clearable 属性
|
* @returns 默认添加 clearable 属性
|
||||||
*/
|
*/
|
||||||
export function setComponentProps(item: VFormSchema): Recordable {
|
export function setComponentProps(item: FormSchema): Recordable {
|
||||||
const notNeedClearable = ['ColorPicker']
|
const notNeedClearable = ['ColorPicker']
|
||||||
const componentProps: Recordable = notNeedClearable.includes(item.component as string)
|
const componentProps: Recordable = notNeedClearable.includes(item.component as string)
|
||||||
? { ...item.componentProps }
|
? { ...item.componentProps }
|
||||||
|
@ -117,7 +117,7 @@ export function setItemComponentSlots(
|
||||||
* @returns FormMoel
|
* @returns FormMoel
|
||||||
* @description 生成对应的formModel
|
* @description 生成对应的formModel
|
||||||
*/
|
*/
|
||||||
export function initModel(schema: VFormSchema[], formModel: Recordable) {
|
export function initModel(schema: FormSchema[], formModel: Recordable) {
|
||||||
const model: Recordable = { ...formModel }
|
const model: Recordable = { ...formModel }
|
||||||
schema.map((v) => {
|
schema.map((v) => {
|
||||||
// 如果是hidden,就删除对应的值
|
// 如果是hidden,就删除对应的值
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
import Icon from './src/Icon.vue'
|
||||||
|
|
||||||
|
export { Icon }
|
|
@ -0,0 +1,86 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed, unref, ref, watch, nextTick } from 'vue'
|
||||||
|
import { ElIcon } from 'element-plus'
|
||||||
|
import { useDesign } from '@/hooks/web/useDesign'
|
||||||
|
import { propTypes } from '@/utils/propTypes'
|
||||||
|
import Iconify from '@purge-icons/generated'
|
||||||
|
|
||||||
|
const { getPrefixCls } = useDesign()
|
||||||
|
|
||||||
|
const prefixCls = getPrefixCls('icon')
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
// icon name
|
||||||
|
icon: propTypes.string,
|
||||||
|
// icon color
|
||||||
|
color: propTypes.string,
|
||||||
|
// icon size
|
||||||
|
size: propTypes.number.def(16)
|
||||||
|
})
|
||||||
|
|
||||||
|
const elRef = ref<ElRef>(null)
|
||||||
|
|
||||||
|
const isLocal = computed(() => props.icon.startsWith('icon:'))
|
||||||
|
|
||||||
|
const symbolId = computed(() => {
|
||||||
|
return unref(isLocal) ? `#icon-${props.icon.split('icon:')[1]}` : props.icon
|
||||||
|
})
|
||||||
|
|
||||||
|
const getIconifyStyle = computed(() => {
|
||||||
|
const { color, size } = props
|
||||||
|
return {
|
||||||
|
fontSize: `${size}px`,
|
||||||
|
color
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
async function updateIcon(icon: string) {
|
||||||
|
if (unref(isLocal)) return
|
||||||
|
|
||||||
|
const el = unref(elRef)
|
||||||
|
if (!el) return
|
||||||
|
|
||||||
|
await nextTick()
|
||||||
|
|
||||||
|
if (!icon) return
|
||||||
|
|
||||||
|
const svg = Iconify.renderSVG(icon, {})
|
||||||
|
if (svg) {
|
||||||
|
el.textContent = ''
|
||||||
|
el.appendChild(svg)
|
||||||
|
} else {
|
||||||
|
const span = document.createElement('span')
|
||||||
|
span.className = 'iconify'
|
||||||
|
span.dataset.icon = icon
|
||||||
|
el.textContent = ''
|
||||||
|
el.appendChild(span)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.icon,
|
||||||
|
(icon: string) => {
|
||||||
|
updateIcon(icon)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<ElIcon :class="[prefixCls, $attrs.class]" :size="size" :color="color">
|
||||||
|
<svg v-if="isLocal" aria-hidden="true">
|
||||||
|
<use :xlink:href="symbolId" />
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
<span v-else ref="elRef" :style="getIconifyStyle">
|
||||||
|
<span class="iconify" :data-icon="symbolId"></span>
|
||||||
|
</span>
|
||||||
|
</ElIcon>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
@prefix-cls: ~'@{namespace}-icon';
|
||||||
|
|
||||||
|
.@{prefix-cls} {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,3 +1,3 @@
|
||||||
import VInputPassword from './src/VInputPassword.vue'
|
import InputPassword from './src/InputPassword.vue'
|
||||||
|
|
||||||
export { VInputPassword }
|
export { InputPassword }
|
||||||
|
|
|
@ -1,12 +1,9 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, unref, computed, watch } from 'vue'
|
import { ref, unref, computed, watch } from 'vue'
|
||||||
import { ElInput, ElIcon } from 'element-plus'
|
import { ElInput } from 'element-plus'
|
||||||
import EyeInvisibleOutlinedE from '~icons/ant-design/eyeInvisibleOutlined'
|
|
||||||
import EyeOutlined from '~icons/ant-design/eye-outlined'
|
|
||||||
import { propTypes } from '@/utils/propTypes'
|
import { propTypes } from '@/utils/propTypes'
|
||||||
import { useDesign } from '@/hooks/web/useDesign'
|
import { useDesign } from '@/hooks/web/useDesign'
|
||||||
import { useConfigGlobal } from '@/hooks/web/useConfigGlobal'
|
import { useConfigGlobal } from '@/hooks/web/useConfigGlobal'
|
||||||
const { configGlobal } = useConfigGlobal()
|
|
||||||
import { zxcvbn } from '@zxcvbn-ts/core'
|
import { zxcvbn } from '@zxcvbn-ts/core'
|
||||||
import type { ZxcvbnResult } from '@zxcvbn-ts/core'
|
import type { ZxcvbnResult } from '@zxcvbn-ts/core'
|
||||||
|
|
||||||
|
@ -16,6 +13,8 @@ defineProps({
|
||||||
modelValue: propTypes.string.def('')
|
modelValue: propTypes.string.def('')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const { configGlobal } = useConfigGlobal()
|
||||||
|
|
||||||
const emit = defineEmits(['update:modelValue'])
|
const emit = defineEmits(['update:modelValue'])
|
||||||
|
|
||||||
// 生成class前缀
|
// 生成class前缀
|
||||||
|
@ -43,16 +42,17 @@ const getPasswordStrength = computed(() => {
|
||||||
const zxcvbnRef = zxcvbn(unref(valueRef)) as ZxcvbnResult
|
const zxcvbnRef = zxcvbn(unref(valueRef)) as ZxcvbnResult
|
||||||
return value ? zxcvbnRef.score : -1
|
return value ? zxcvbnRef.score : -1
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const getIconName = computed(() =>
|
||||||
|
unref(textType) === 'password' ? 'ant-design:eye-invisible-outlined' : 'ant-design:eye-outlined'
|
||||||
|
)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div :class="[prefixCls, `${prefixCls}--${configGlobal?.size}`]">
|
<div :class="[prefixCls, `${prefixCls}--${configGlobal?.size}`]">
|
||||||
<ElInput v-bind="$attrs" v-model="valueRef" :type="textType">
|
<ElInput v-bind="$attrs" v-model="valueRef" :type="textType">
|
||||||
<template #suffix>
|
<template #suffix>
|
||||||
<ElIcon class="el-input__icon el-input__clear">
|
<Icon class="el-input__icon" :icon="getIconName" @click="changeTextType" />
|
||||||
<EyeInvisibleOutlinedE v-if="textType === 'password'" @click="changeTextType" />
|
|
||||||
<EyeOutlined v-else @click="changeTextType" />
|
|
||||||
</ElIcon>
|
|
||||||
</template>
|
</template>
|
||||||
</ElInput>
|
</ElInput>
|
||||||
<div
|
<div
|
||||||
|
@ -69,6 +69,10 @@ const getPasswordStrength = computed(() => {
|
||||||
@prefix-cls: ~'@{namespace}-input-password';
|
@prefix-cls: ~'@{namespace}-input-password';
|
||||||
|
|
||||||
.@{prefix-cls} {
|
.@{prefix-cls} {
|
||||||
|
:deep(.el-input__clear) {
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
&__bar {
|
&__bar {
|
||||||
background-color: var(--el-text-color-disabled-base);
|
background-color: var(--el-text-color-disabled-base);
|
||||||
border-radius: var(--el-border-radius-base);
|
border-radius: var(--el-border-radius-base);
|
|
@ -1,3 +1,3 @@
|
||||||
import VLocaleDropdown from './src/VLocaleDropdown.vue'
|
import LocaleDropdown from './src/LocaleDropdown.vue'
|
||||||
|
|
||||||
export { VLocaleDropdown }
|
export { LocaleDropdown }
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed } from 'vue'
|
||||||
|
import { ElDropdown, ElDropdownMenu, ElDropdownItem } from 'element-plus'
|
||||||
|
import { useLocaleStore } from '@/store/modules/locale'
|
||||||
|
import { useCssVar } from '@vueuse/core'
|
||||||
|
import { useLocale } from '@/hooks/web/useLocale'
|
||||||
|
|
||||||
|
const localeStore = useLocaleStore()
|
||||||
|
|
||||||
|
const langMap = computed(() => localeStore.localeMap)
|
||||||
|
|
||||||
|
const textColor = useCssVar('--el-text-color-primary', document.documentElement)
|
||||||
|
|
||||||
|
function setLang(lang: LocaleType) {
|
||||||
|
localeStore.setLocale({
|
||||||
|
lang
|
||||||
|
})
|
||||||
|
const { changeLocale } = useLocale()
|
||||||
|
changeLocale(lang)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<ElDropdown trigger="click" @command="setLang">
|
||||||
|
<Icon icon="ion:language-sharp" :color="textColor" class="cursor-pointer" />
|
||||||
|
<template #dropdown>
|
||||||
|
<ElDropdownMenu>
|
||||||
|
<ElDropdownItem v-for="item in langMap" :key="item.lang" :command="item.lang">
|
||||||
|
{{ item.name }}
|
||||||
|
</ElDropdownItem>
|
||||||
|
</ElDropdownMenu>
|
||||||
|
</template>
|
||||||
|
</ElDropdown>
|
||||||
|
</template>
|
|
@ -1,19 +0,0 @@
|
||||||
<script setup lang="ts"></script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div>s</div>
|
|
||||||
<!-- <el-dropdown trigger="click">
|
|
||||||
<span class="el-dropdown-link">
|
|
||||||
Dropdown List<el-icon class="el-icon--right"><arrow-down /></el-icon>
|
|
||||||
</span>
|
|
||||||
<template #dropdown>
|
|
||||||
<el-dropdown-menu>
|
|
||||||
<el-dropdown-item :icon="Plus">Action 1</el-dropdown-item>
|
|
||||||
<el-dropdown-item :icon="CirclePlusFilled"> Action 2 </el-dropdown-item>
|
|
||||||
<el-dropdown-item :icon="CirclePlus">Action 3</el-dropdown-item>
|
|
||||||
<el-dropdown-item :icon="Check">Action 4</el-dropdown-item>
|
|
||||||
<el-dropdown-item :icon="CircleCheck">Action 5</el-dropdown-item>
|
|
||||||
</el-dropdown-menu>
|
|
||||||
</template>
|
|
||||||
</el-dropdown> -->
|
|
||||||
</template>
|
|
|
@ -1,3 +1,3 @@
|
||||||
import VThemeSwitch from './src/VThemeSwitch.vue'
|
import ThemeSwitch from './src/ThemeSwitch.vue'
|
||||||
|
|
||||||
export { VThemeSwitch }
|
export { ThemeSwitch }
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { useAppStore } from '@/store/modules/app'
|
import { useAppStore } from '@/store/modules/app'
|
||||||
import Sun from '~icons/emojione-monotone/sun'
|
|
||||||
import CrescentMoon from '~icons/emojione-monotone/crescent-moon'
|
|
||||||
import { ElSwitch } from 'element-plus'
|
import { ElSwitch } from 'element-plus'
|
||||||
import { useCssVar } from '@vueuse/core'
|
import { useCssVar } from '@vueuse/core'
|
||||||
import { useDesign } from '@/hooks/web/useDesign'
|
import { useDesign } from '@/hooks/web/useDesign'
|
||||||
|
import { useIcon } from '@/hooks/web/useIcon'
|
||||||
|
|
||||||
|
const Sun = useIcon({ icon: 'emojione-monotone:sun' })
|
||||||
|
const CrescentMoon = useIcon({ icon: 'emojione-monotone:crescent-moon' })
|
||||||
|
|
||||||
const appStore = useAppStore()
|
const appStore = useAppStore()
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
import type { App } from 'vue'
|
||||||
|
import { Icon } from './Icon'
|
||||||
|
|
||||||
|
export function setupGlobCom(app: App<Element>): void {
|
||||||
|
app.component('Icon', Icon)
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
import { inject } from 'vue'
|
import { inject } from 'vue'
|
||||||
|
|
||||||
export function useConfigGlobal() {
|
export function useConfigGlobal() {
|
||||||
const configGlobal = inject('configGlobal', {}) as VConfigGlobalTypes
|
const configGlobal = inject('configGlobal', {}) as ConfigGlobalTypes
|
||||||
|
|
||||||
return {
|
return {
|
||||||
configGlobal
|
configGlobal
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
import { h } from 'vue'
|
||||||
|
import type { VNode } from 'vue'
|
||||||
|
import { Icon } from '@/components/Icon'
|
||||||
|
|
||||||
|
export function useIcon(props: IconTypes): VNode {
|
||||||
|
return h(Icon, props)
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
import { i18n } from '@/plugins/i18n'
|
||||||
|
import { useLocaleStoreWithOut } from '@/store/modules/locale'
|
||||||
|
import { setHtmlPageLang } from '@/plugins/i18n/helper'
|
||||||
|
|
||||||
|
function setI18nLanguage(locale: LocaleType) {
|
||||||
|
const localeStore = useLocaleStoreWithOut()
|
||||||
|
|
||||||
|
if (i18n.mode === 'legacy') {
|
||||||
|
i18n.global.locale = locale
|
||||||
|
} else {
|
||||||
|
;(i18n.global.locale as any).value = locale
|
||||||
|
}
|
||||||
|
localeStore.setLocale({
|
||||||
|
lang: locale
|
||||||
|
})
|
||||||
|
setHtmlPageLang(locale)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useLocale() {
|
||||||
|
// Switching the language will change the locale of useI18n
|
||||||
|
// And submit to configuration modification
|
||||||
|
async function changeLocale(locale: LocaleType) {
|
||||||
|
const globalI18n = i18n.global
|
||||||
|
|
||||||
|
const langModule = (await import(`../../locales/${locale}.ts`)) as any
|
||||||
|
|
||||||
|
globalI18n.setLocaleMessage(locale, langModule.default)
|
||||||
|
|
||||||
|
setI18nLanguage(locale)
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
changeLocale
|
||||||
|
}
|
||||||
|
}
|
42
src/main.ts
42
src/main.ts
|
@ -1,22 +1,42 @@
|
||||||
// 引入windi css
|
// 引入windi css
|
||||||
import '@/plugins/windicss'
|
import '@/plugins/windicss'
|
||||||
|
|
||||||
import { createApp } from 'vue'
|
// 导入全局的svg图标
|
||||||
import App from './App.vue'
|
import '@/plugins/svgIcon'
|
||||||
const app = createApp(App)
|
|
||||||
|
|
||||||
// 引入element-plus
|
// 初始化多语言
|
||||||
import { setupElementPlus } from '@/plugins/elementPlus'
|
import { setupI18n } from '@/plugins/i18n'
|
||||||
setupElementPlus(app)
|
|
||||||
|
|
||||||
// 引入状态管理
|
// 引入状态管理
|
||||||
import { setupStore } from '@/store'
|
import { setupStore } from '@/store'
|
||||||
setupStore(app)
|
|
||||||
|
// 全局组件
|
||||||
|
import { setupGlobCom } from '@/components'
|
||||||
|
|
||||||
|
// 引入element-plus
|
||||||
|
import { setupElementPlus } from '@/plugins/elementPlus'
|
||||||
|
|
||||||
// 路由
|
// 路由
|
||||||
import router, { setupRouter } from './router'
|
import { setupRouter } from './router'
|
||||||
setupRouter(app)
|
|
||||||
|
import { createApp } from 'vue'
|
||||||
|
|
||||||
|
import App from './App.vue'
|
||||||
|
|
||||||
|
async function setupAll() {
|
||||||
|
const app = createApp(App)
|
||||||
|
|
||||||
|
await setupI18n(app)
|
||||||
|
|
||||||
|
setupStore(app)
|
||||||
|
|
||||||
|
setupGlobCom(app)
|
||||||
|
|
||||||
|
setupElementPlus(app)
|
||||||
|
|
||||||
|
setupRouter(app)
|
||||||
|
|
||||||
router.isReady().then(() => {
|
|
||||||
app.mount('#app')
|
app.mount('#app')
|
||||||
})
|
}
|
||||||
|
|
||||||
|
setupAll()
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
export function setHtmlPageLang(locale: LocaleType) {
|
||||||
|
document.querySelector('html')?.setAttribute('lang', locale)
|
||||||
|
}
|
|
@ -1,16 +1,42 @@
|
||||||
|
import type { App } from 'vue'
|
||||||
import { createI18n } from 'vue-i18n'
|
import { createI18n } from 'vue-i18n'
|
||||||
|
import { useLocaleStoreWithOut } from '@/store/modules/locale'
|
||||||
|
import type { I18n, I18nOptions } from 'vue-i18n'
|
||||||
|
import { setHtmlPageLang } from './helper'
|
||||||
|
|
||||||
export const i18n = setupI18n()
|
export let i18n: ReturnType<typeof createI18n>
|
||||||
|
|
||||||
function setupI18n() {
|
async function createI18nOptions(): Promise<I18nOptions> {
|
||||||
const messages = Object.fromEntries(
|
const localeStore = useLocaleStoreWithOut()
|
||||||
Object.entries(import.meta.globEager('../../locales/*.ts')).map(([key, value]) => {
|
const locale = localeStore.getLocale
|
||||||
return [key.slice(14, -3), value.default]
|
const localeMap = localeStore.getLocaleMap
|
||||||
|
const defaultLocal = await import(`../../locales/${locale.lang}.ts`)
|
||||||
|
const message = defaultLocal.default ?? {}
|
||||||
|
|
||||||
|
setHtmlPageLang(locale.lang)
|
||||||
|
|
||||||
|
localeStore.setLocale({
|
||||||
|
lang: locale.lang
|
||||||
|
// elLocale: elLocal
|
||||||
})
|
})
|
||||||
)
|
|
||||||
return createI18n({
|
return {
|
||||||
legacy: false,
|
legacy: false,
|
||||||
locale: 'zh-CN',
|
locale: locale.lang,
|
||||||
messages
|
fallbackLocale: locale.lang,
|
||||||
})
|
messages: {
|
||||||
|
[locale.lang]: message
|
||||||
|
},
|
||||||
|
availableLocales: localeMap.map((v) => v.lang),
|
||||||
|
sync: true,
|
||||||
|
silentTranslationWarn: true,
|
||||||
|
missingWarn: false,
|
||||||
|
silentFallbackWarn: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function setupI18n(app: App) {
|
||||||
|
const options = await createI18nOptions()
|
||||||
|
i18n = createI18n(options) as I18n
|
||||||
|
app.use(i18n)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
import 'virtual:svg-icons-register'
|
||||||
|
|
||||||
|
import '@purge-icons/generated'
|
|
@ -2,8 +2,7 @@ import { createRouter, createWebHashHistory } from 'vue-router'
|
||||||
import type { RouteRecordRaw } from 'vue-router'
|
import type { RouteRecordRaw } from 'vue-router'
|
||||||
import type { App } from 'vue'
|
import type { App } from 'vue'
|
||||||
// import { getParentLayout } from './helper'
|
// import { getParentLayout } from './helper'
|
||||||
import { useI18n } from '@/hooks/web/useI18n'
|
import { t } from '@/hooks/web/useI18n'
|
||||||
const { t } = useI18n()
|
|
||||||
|
|
||||||
export const constantRouterMap: AppRouteRecordRaw[] = [
|
export const constantRouterMap: AppRouteRecordRaw[] = [
|
||||||
{
|
{
|
||||||
|
@ -20,7 +19,7 @@ export const constantRouterMap: AppRouteRecordRaw[] = [
|
||||||
|
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
history: createWebHashHistory(),
|
history: createWebHashHistory(),
|
||||||
strict: false,
|
strict: true,
|
||||||
routes: constantRouterMap as RouteRecordRaw[],
|
routes: constantRouterMap as RouteRecordRaw[],
|
||||||
scrollBehavior: () => ({ left: 0, top: 0 })
|
scrollBehavior: () => ({ left: 0, top: 0 })
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
|
|
||||||
import { store } from '../index'
|
import { store } from '../index'
|
||||||
|
|
||||||
export type LayoutType = 'Classic' | 'LeftTop' | 'Top' | 'Test'
|
export type LayoutType = 'Classic' | 'LeftTop' | 'Top' | 'Test'
|
||||||
|
@ -24,7 +23,6 @@ export interface AppState {
|
||||||
requestTime: boolean
|
requestTime: boolean
|
||||||
isDark: boolean
|
isDark: boolean
|
||||||
size: ElememtPlusSzie
|
size: ElememtPlusSzie
|
||||||
lang: string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useAppStore = defineStore({
|
export const useAppStore = defineStore({
|
||||||
|
@ -48,8 +46,7 @@ export const useAppStore = defineStore({
|
||||||
showMenuTab: false, // 是否固定一级菜单
|
showMenuTab: false, // 是否固定一级菜单
|
||||||
requestTime: false, // 是否在接口调用时添加时间戳,避免IE缓存
|
requestTime: false, // 是否在接口调用时添加时间戳,避免IE缓存
|
||||||
isDark: false, // 是否是暗黑模式
|
isDark: false, // 是否是暗黑模式
|
||||||
size: 'default', // 组件尺寸
|
size: 'default' // 组件尺寸
|
||||||
lang: 'zh-CN' // 语言
|
|
||||||
}),
|
}),
|
||||||
getters: {
|
getters: {
|
||||||
getCollapsed(): boolean {
|
getCollapsed(): boolean {
|
||||||
|
@ -108,9 +105,6 @@ export const useAppStore = defineStore({
|
||||||
},
|
},
|
||||||
getSize(): ElememtPlusSzie {
|
getSize(): ElememtPlusSzie {
|
||||||
return this.size
|
return this.size
|
||||||
},
|
|
||||||
getLang(): string {
|
|
||||||
return this.lang
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
|
@ -174,9 +168,6 @@ export const useAppStore = defineStore({
|
||||||
},
|
},
|
||||||
setSize(size: ElememtPlusSzie) {
|
setSize(size: ElememtPlusSzie) {
|
||||||
this.size = size
|
this.size = size
|
||||||
},
|
|
||||||
setLang(lang: string) {
|
|
||||||
this.lang = lang
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
import { defineStore } from 'pinia'
|
||||||
|
import zhCn from 'element-plus/lib/locale/lang/zh-cn'
|
||||||
|
import en from 'element-plus/lib/locale/lang/en'
|
||||||
|
import { store } from '../index'
|
||||||
|
|
||||||
|
const elLocaleMap = {
|
||||||
|
'zh-CN': zhCn,
|
||||||
|
en: en
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LocaleState {
|
||||||
|
locale: LocaleDropdownType
|
||||||
|
localeMap: LocaleDropdownType[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useLocaleStore = defineStore({
|
||||||
|
id: 'locales',
|
||||||
|
state: (): LocaleState => ({
|
||||||
|
// 当前语言
|
||||||
|
locale: {
|
||||||
|
lang: 'zh-CN',
|
||||||
|
elLocale: elLocaleMap['zh-CN']
|
||||||
|
},
|
||||||
|
// 多语言
|
||||||
|
localeMap: [
|
||||||
|
{
|
||||||
|
lang: 'zh-CN',
|
||||||
|
name: '简体中文'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lang: 'en',
|
||||||
|
name: 'English'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
getters: {
|
||||||
|
getLocale(): LocaleDropdownType {
|
||||||
|
return this.locale
|
||||||
|
},
|
||||||
|
getLocaleMap(): LocaleDropdownType[] {
|
||||||
|
return this.localeMap
|
||||||
|
}
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
setLocale(localeMap: LocaleDropdownType) {
|
||||||
|
// this.locale = Object.assign(this.locale, localeMap)
|
||||||
|
this.locale.lang = localeMap?.lang
|
||||||
|
this.locale.elLocale = elLocaleMap[localeMap?.lang]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export function useLocaleStoreWithOut() {
|
||||||
|
return useLocaleStore(store)
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
.text-color {
|
||||||
|
color: var(--el-text-color-regular);
|
||||||
|
}
|
||||||
|
.dark .dark\:text-color {
|
||||||
|
color: rgba(255, 255, 255, var(--dark-text-color));
|
||||||
|
}
|
|
@ -1,2 +1,3 @@
|
||||||
:root {
|
:root {
|
||||||
|
--dark-text-color: #c9d1d9;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ import type { CSSProperties } from 'vue'
|
||||||
import type { RuleItem } from 'async-validator'
|
import type { RuleItem } from 'async-validator'
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
// BfForm types start
|
// Form types start
|
||||||
declare type ComponentName =
|
declare type ComponentName =
|
||||||
| 'Radio'
|
| 'Radio'
|
||||||
| 'RadioButton'
|
| 'RadioButton'
|
||||||
|
@ -75,7 +75,7 @@ declare global {
|
||||||
optionsSlot?: boolean
|
optionsSlot?: boolean
|
||||||
} & Recordable
|
} & Recordable
|
||||||
|
|
||||||
declare type VFormSchema = {
|
declare type FormSchema = {
|
||||||
// 唯一值
|
// 唯一值
|
||||||
field: string
|
field: string
|
||||||
// 标题
|
// 标题
|
||||||
|
@ -93,11 +93,32 @@ declare global {
|
||||||
// 是否隐藏
|
// 是否隐藏
|
||||||
hidden?: boolean
|
hidden?: boolean
|
||||||
}
|
}
|
||||||
// VForm types end
|
// Form types end
|
||||||
|
|
||||||
// VConfigGlobal types start
|
// ConfigGlobal types start
|
||||||
declare interface VConfigGlobalTypes {
|
declare interface ConfigGlobalTypes {
|
||||||
size?: ElememtPlusSzie
|
size?: ElememtPlusSzie
|
||||||
}
|
}
|
||||||
// VConfigGlobal types end
|
// ConfigGlobal types end
|
||||||
|
|
||||||
|
// Icon type start
|
||||||
|
declare interface IconTypes {
|
||||||
|
size?: number
|
||||||
|
color?: string
|
||||||
|
icon: string
|
||||||
|
}
|
||||||
|
// Icon type end
|
||||||
|
|
||||||
|
// LocaleDropdown type start
|
||||||
|
declare interface Language {
|
||||||
|
el: Recordable
|
||||||
|
name: string
|
||||||
|
}
|
||||||
|
|
||||||
|
declare interface LocaleDropdownType {
|
||||||
|
lang: LocaleType
|
||||||
|
name?: string
|
||||||
|
elLocale?: Language
|
||||||
|
}
|
||||||
|
// LocaleDropdown type end
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
declare module 'vue' {
|
||||||
|
export interface GlobalComponents {
|
||||||
|
Icon: typeof import('../components/Icon/src/Icon.vue')['default']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export {}
|
|
@ -6,10 +6,12 @@ declare type Nullable<T> = T | null
|
||||||
|
|
||||||
declare type ElRef<T extends HTMLElement = HTMLDivElement> = Nullable<T>
|
declare type ElRef<T extends HTMLElement = HTMLDivElement> = Nullable<T>
|
||||||
|
|
||||||
declare type ElememtPlusSzie = 'default' | 'medium' | 'small' | 'mini'
|
declare type ElememtPlusSzie = 'default' | 'small' | 'large'
|
||||||
|
|
||||||
declare type ElementPlusInfoType = 'success' | 'info' | 'warning' | 'danger'
|
declare type ElementPlusInfoType = 'success' | 'info' | 'warning' | 'danger'
|
||||||
|
|
||||||
declare type Recordable<T = any, K = string> = Record<K extends null | undefined ? string : K, T>
|
declare type Recordable<T = any, K = string> = Record<K extends null | undefined ? string : K, T>
|
||||||
|
|
||||||
declare type ComponentRef<T> = InstanceType<T>
|
declare type ComponentRef<T> = InstanceType<T>
|
||||||
|
|
||||||
|
declare type LocaleType = 'zh-CN' | 'en'
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { VThemeSwitch } from '@/components/ThemeSwitch'
|
import { ThemeSwitch } from '@/components/ThemeSwitch'
|
||||||
|
import { LocaleDropdown } from '@/components/LocaleDropdown'
|
||||||
import { useDesign } from '@/hooks/web/useDesign'
|
import { useDesign } from '@/hooks/web/useDesign'
|
||||||
import { useI18n } from '@/hooks/web/useI18n'
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
|
import { ElCalendar } from 'element-plus'
|
||||||
|
import { VFrom } from '@/components/Form'
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
const { getPrefixCls } = useDesign()
|
const { getPrefixCls } = useDesign()
|
||||||
|
@ -10,7 +14,20 @@ const prefixCls = getPrefixCls('login')
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div :class="prefixCls" class="h-[calc(100%)] relative">
|
<div :class="prefixCls" class="h-[calc(100%)] relative">
|
||||||
<VThemeSwitch />
|
<Icon icon="icon:icon" />
|
||||||
|
<Icon icon="ant-design:eye-outlined" />
|
||||||
|
<ThemeSwitch />
|
||||||
|
<LocaleDropdown />
|
||||||
|
<ElCalendar />
|
||||||
|
<VFrom
|
||||||
|
:schema="[
|
||||||
|
{
|
||||||
|
label: 'input',
|
||||||
|
field: 'field1',
|
||||||
|
component: 'InputPassword'
|
||||||
|
}
|
||||||
|
]"
|
||||||
|
/>
|
||||||
{{ t('formDemo.default') }}
|
{{ t('formDemo.default') }}
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -23,14 +23,9 @@
|
||||||
"paths": {
|
"paths": {
|
||||||
"@/*": ["src/*"]
|
"@/*": ["src/*"]
|
||||||
},
|
},
|
||||||
"types": [
|
"types": ["@intlify/vite-plugin-vue-i18n/client", "vite/client", "element-plus/global"],
|
||||||
"@intlify/vite-plugin-vue-i18n/client",
|
|
||||||
"vite/client",
|
|
||||||
"element-plus/global",
|
|
||||||
"unplugin-icons/types/vue"
|
|
||||||
],
|
|
||||||
"typeRoots": ["./node_modules/@types/", "./src/types"]
|
"typeRoots": ["./node_modules/@types/", "./src/types"]
|
||||||
},
|
},
|
||||||
"include": ["src/**/*"],
|
"include": ["./src/**/*"],
|
||||||
"exclude": ["dist", "node_modules"]
|
"exclude": ["dist", "node_modules"]
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,8 +6,9 @@ import WindiCSS from 'vite-plugin-windicss'
|
||||||
import VueJsx from '@vitejs/plugin-vue-jsx'
|
import VueJsx from '@vitejs/plugin-vue-jsx'
|
||||||
import EslintPlugin from 'vite-plugin-eslint'
|
import EslintPlugin from 'vite-plugin-eslint'
|
||||||
import VueI18n from '@intlify/vite-plugin-vue-i18n'
|
import VueI18n from '@intlify/vite-plugin-vue-i18n'
|
||||||
import Icons from 'unplugin-icons/vite'
|
|
||||||
import StyleImport, { ElementPlusResolve } from 'vite-plugin-style-import'
|
import StyleImport, { ElementPlusResolve } from 'vite-plugin-style-import'
|
||||||
|
import ViteSvgIcons from 'vite-plugin-svg-icons'
|
||||||
|
import PurgeIcons from 'vite-plugin-purge-icons'
|
||||||
|
|
||||||
// https://vitejs.dev/config/
|
// https://vitejs.dev/config/
|
||||||
const root = process.cwd()
|
const root = process.cwd()
|
||||||
|
@ -41,10 +42,6 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
|
||||||
}
|
}
|
||||||
}]
|
}]
|
||||||
}),
|
}),
|
||||||
Icons({
|
|
||||||
compiler: 'vue3',
|
|
||||||
autoInstall: true
|
|
||||||
}),
|
|
||||||
EslintPlugin({
|
EslintPlugin({
|
||||||
cache: false,
|
cache: false,
|
||||||
include: ['src/**/*.vue', 'src/**/*.ts', 'src/**/*.tsx'] // 检查的文件
|
include: ['src/**/*.vue', 'src/**/*.ts', 'src/**/*.tsx'] // 检查的文件
|
||||||
|
@ -53,7 +50,13 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
|
||||||
runtimeOnly: true,
|
runtimeOnly: true,
|
||||||
compositionOnly: true,
|
compositionOnly: true,
|
||||||
include: [resolve(__dirname, 'src/locales/**')]
|
include: [resolve(__dirname, 'src/locales/**')]
|
||||||
})
|
}),
|
||||||
|
ViteSvgIcons({
|
||||||
|
iconDirs: [pathResolve('src/assets/svgs')],
|
||||||
|
symbolId: 'icon-[dir]-[name]',
|
||||||
|
svgoOptions: true
|
||||||
|
}),
|
||||||
|
PurgeIcons()
|
||||||
],
|
],
|
||||||
|
|
||||||
css: {
|
css: {
|
||||||
|
@ -116,7 +119,8 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
|
||||||
'vue-router',
|
'vue-router',
|
||||||
'vue-types',
|
'vue-types',
|
||||||
'element-plus/lib/locale/lang/zh-cn',
|
'element-plus/lib/locale/lang/zh-cn',
|
||||||
'element-plus/lib/locale/lang/en'
|
'element-plus/lib/locale/lang/en',
|
||||||
|
'@iconify/iconify'
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue