39 changed files with 367 additions and 456 deletions
@ -1,15 +1,14 @@ |
|||
import { withInstall } from '../util'; |
|||
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent'; |
|||
import AppLogo from './src/AppLogo.vue'; |
|||
import AppProvider from './src/AppProvider.vue'; |
|||
import { withInstall } from '../util'; |
|||
|
|||
export const AppLocalePicker = createAsyncComponent(() => import('./src/AppLocalePicker.vue')); |
|||
export const AppProvider = createAsyncComponent(() => import('./src/AppProvider.vue')); |
|||
export const AppSearch = createAsyncComponent(() => import('./src/search/AppSearch.vue'), { |
|||
loading: true, |
|||
}); |
|||
// export const AppLogo = createAsyncComponent(() => import('./src/AppLogo.vue'));
|
|||
|
|||
withInstall(AppLocalePicker, AppLogo, AppProvider, AppSearch); |
|||
|
|||
export { useAppProviderContext } from './src/useAppContext'; |
|||
export { AppLogo }; |
|||
export { AppLogo, AppProvider }; |
|||
|
|||
withInstall(AppLogo, AppProvider); |
|||
|
|||
@ -1,6 +1,7 @@ |
|||
import { withInstall } from '../util'; |
|||
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent'; |
|||
|
|||
export const Authority = createAsyncComponent(() => import('./src/index.vue')); |
|||
import Authority from './src/index.vue'; |
|||
|
|||
withInstall(Authority); |
|||
|
|||
export { Authority }; |
|||
|
|||
@ -1,6 +1,7 @@ |
|||
import { withInstall } from '../util'; |
|||
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent'; |
|||
|
|||
export const ClickOutSide = createAsyncComponent(() => import('./src/index.vue')); |
|||
import ClickOutSide from './src/index.vue'; |
|||
|
|||
withInstall(ClickOutSide); |
|||
|
|||
export { ClickOutSide }; |
|||
|
|||
@ -1,14 +1,8 @@ |
|||
import { withInstall } from '../util'; |
|||
import CollapseContainer from './src/collapse/CollapseContainer.vue'; |
|||
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent'; |
|||
export const ScrollContainer = createAsyncComponent(() => import('./src/ScrollContainer.vue')); |
|||
|
|||
// export const CollapseContainer = createAsyncComponent(
|
|||
// () => import('./src/collapse/CollapseContainer.vue')
|
|||
// );
|
|||
export const LazyContainer = createAsyncComponent(() => import('./src/LazyContainer.vue')); |
|||
import ScrollContainer from './src/ScrollContainer.vue'; |
|||
import LazyContainer from './src/LazyContainer.vue'; |
|||
|
|||
withInstall(ScrollContainer, CollapseContainer, LazyContainer); |
|||
|
|||
export { CollapseContainer }; |
|||
export { CollapseContainer, ScrollContainer, LazyContainer }; |
|||
export * from './src/types'; |
|||
|
|||
@ -1,9 +1,5 @@ |
|||
import { withInstall } from '../util'; |
|||
|
|||
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent'; |
|||
export const Description = createAsyncComponent(() => import('./src/index')); |
|||
|
|||
withInstall(Description); |
|||
|
|||
export * from './src/types'; |
|||
export { useDescription } from './src/useDescription'; |
|||
|
|||
@ -1,8 +1,9 @@ |
|||
import { withInstall } from '../util'; |
|||
|
|||
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent'; |
|||
export const BasicDrawer = createAsyncComponent(() => import('./src/BasicDrawer')); |
|||
import BasicDrawer from './src/BasicDrawer'; |
|||
|
|||
withInstall(BasicDrawer); |
|||
export { BasicDrawer }; |
|||
export * from './src/types'; |
|||
export { useDrawer, useDrawerInner } from './src/useDrawer'; |
|||
|
|||
withInstall(BasicDrawer); |
|||
|
|||
@ -1,57 +0,0 @@ |
|||
import type { Trigger } from './types'; |
|||
|
|||
import { defineComponent, computed, unref } from 'vue'; |
|||
import { Dropdown, Menu } from 'ant-design-vue'; |
|||
import Icon from '/@/components/Icon/index'; |
|||
|
|||
import { basicDropdownProps } from './props'; |
|||
import { getSlot } from '/@/utils/helper/tsxHelper'; |
|||
|
|||
export default defineComponent({ |
|||
name: 'Dropdown', |
|||
props: basicDropdownProps, |
|||
emits: ['menuEvent'], |
|||
setup(props, { slots, emit, attrs }) { |
|||
const getMenuList = computed(() => props.dropMenuList); |
|||
|
|||
function handleClickMenu({ key }: any) { |
|||
const menu = unref(getMenuList).find((item) => `${item.event}` === `${key}`); |
|||
emit('menuEvent', menu); |
|||
} |
|||
|
|||
function renderMenus() { |
|||
return ( |
|||
<Menu onClick={handleClickMenu} selectedKeys={props.selectedKeys}> |
|||
{() => ( |
|||
<> |
|||
{unref(getMenuList).map((item) => { |
|||
const { disabled, icon, text, divider, event } = item; |
|||
return [ |
|||
<Menu.Item key={`${event}`} disabled={disabled}> |
|||
{() => ( |
|||
<> |
|||
{icon && <Icon icon={icon} />} |
|||
<span class="ml-1">{text}</span> |
|||
</> |
|||
)} |
|||
</Menu.Item>, |
|||
// @ts-ignore
|
|||
divider && <Menu.Divider key={`d-${event}`} />, |
|||
]; |
|||
})} |
|||
</> |
|||
)} |
|||
</Menu> |
|||
); |
|||
} |
|||
|
|||
return () => ( |
|||
<Dropdown trigger={props.trigger as Trigger[]} {...attrs}> |
|||
{{ |
|||
default: () => <span>{getSlot(slots)}</span>, |
|||
overlay: () => renderMenus(), |
|||
}} |
|||
</Dropdown> |
|||
); |
|||
}, |
|||
}); |
|||
@ -0,0 +1,70 @@ |
|||
<template> |
|||
<a-dropdown :trigger="trigger" v-bind="$attrs"> |
|||
<span> |
|||
<slot /> |
|||
</span> |
|||
<template #overlay> |
|||
<a-menu :selectedKeys="selectedKeys"> |
|||
<template v-for="item in getMenuList" :key="`${item.event}`"> |
|||
<a-menu-item @click="handleClickMenu({ key: item.event })" :disabled="item.disabled"> |
|||
<Icon :icon="item.icon" v-if="item.icon" /> |
|||
<span class="ml-1">{{ item.text }}</span> |
|||
</a-menu-item> |
|||
<a-menu-divider v-if="item.divider" :key="`d-${item.event}`" /> |
|||
</template> |
|||
</a-menu> |
|||
</template> |
|||
</a-dropdown> |
|||
</template> |
|||
|
|||
<script lang="ts"> |
|||
import type { PropType } from 'vue'; |
|||
import type { DropMenu } from './types'; |
|||
|
|||
import { defineComponent, computed, unref } from 'vue'; |
|||
import { Dropdown, Menu } from 'ant-design-vue'; |
|||
import Icon from '/@/components/Icon/index'; |
|||
|
|||
export default defineComponent({ |
|||
name: 'BasicDropdown', |
|||
components: { |
|||
[Dropdown.name]: Dropdown, |
|||
[Menu.name]: Menu, |
|||
[Menu.Item.name]: Menu.Item, |
|||
[Menu.Divider.name]: Menu.Divider, |
|||
Icon, |
|||
}, |
|||
props: { |
|||
/** |
|||
* the trigger mode which executes the drop-down action |
|||
* @default ['hover'] |
|||
* @type string[] |
|||
*/ |
|||
trigger: { |
|||
type: [Array] as PropType<string[]>, |
|||
default: () => { |
|||
return ['contextmenu']; |
|||
}, |
|||
}, |
|||
dropMenuList: { |
|||
type: Array as PropType<DropMenu[]>, |
|||
default: () => [], |
|||
}, |
|||
selectedKeys: { |
|||
type: Array as PropType<string[]>, |
|||
default: () => [], |
|||
}, |
|||
}, |
|||
emits: ['menuEvent'], |
|||
setup(props, { emit }) { |
|||
const getMenuList = computed(() => props.dropMenuList); |
|||
|
|||
function handleClickMenu({ key }: { key: string }) { |
|||
const menu = unref(getMenuList).find((item) => `${item.event}` === `${key}`); |
|||
emit('menuEvent', menu); |
|||
} |
|||
|
|||
return { handleClickMenu, getMenuList }; |
|||
}, |
|||
}); |
|||
</script> |
|||
@ -1,26 +0,0 @@ |
|||
import type { PropType } from 'vue'; |
|||
import type { DropMenu } from './types'; |
|||
|
|||
export const dropdownProps = { |
|||
/** |
|||
* the trigger mode which executes the drop-down action |
|||
* @default ['hover'] |
|||
* @type string[] |
|||
*/ |
|||
trigger: { |
|||
type: [Array] as PropType<string[]>, |
|||
default: () => { |
|||
return ['contextmenu']; |
|||
}, |
|||
}, |
|||
}; |
|||
export const basicDropdownProps = Object.assign({}, dropdownProps, { |
|||
dropMenuList: { |
|||
type: Array as PropType<DropMenu[]>, |
|||
default: () => [], |
|||
}, |
|||
selectedKeys: { |
|||
type: Array as PropType<string[]>, |
|||
default: () => [], |
|||
}, |
|||
}); |
|||
@ -1,12 +1,8 @@ |
|||
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent'; |
|||
|
|||
import { withInstall } from '../util'; |
|||
|
|||
export const ImpExcel = createAsyncComponent(() => import('./src/ImportExcel.vue')); |
|||
export const ExpExcelModel = createAsyncComponent(() => import('./src/ExportExcelModel.vue')); |
|||
|
|||
withInstall(ImpExcel, ExpExcelModel); |
|||
|
|||
export * from './src/types'; |
|||
|
|||
export { jsonToSheetXlsx, aoaToSheetXlsx } from './src/Export2Excel'; |
|||
|
|||
@ -1,14 +0,0 @@ |
|||
@import (reference) '../../design/index.less'; |
|||
|
|||
.app-iconify { |
|||
display: inline-block; |
|||
vertical-align: middle; |
|||
} |
|||
|
|||
span.iconify { |
|||
display: block; |
|||
min-width: 1em; |
|||
min-height: 1em; |
|||
background: @iconify-bg-color; |
|||
border-radius: 100%; |
|||
} |
|||
@ -0,0 +1,7 @@ |
|||
import { withInstall } from '../util'; |
|||
import Icon from './src/index.vue'; |
|||
|
|||
withInstall(Icon); |
|||
|
|||
export { Icon }; |
|||
export default Icon; |
|||
@ -1,83 +0,0 @@ |
|||
import './index.less'; |
|||
|
|||
import type { PropType } from 'vue'; |
|||
import { |
|||
defineComponent, |
|||
ref, |
|||
watch, |
|||
onMounted, |
|||
nextTick, |
|||
unref, |
|||
computed, |
|||
CSSProperties, |
|||
} from 'vue'; |
|||
import Iconify from '@purge-icons/generated'; |
|||
import { isString } from '/@/utils/is'; |
|||
import { propTypes } from '/@/utils/propTypes'; |
|||
export default defineComponent({ |
|||
name: 'GIcon', |
|||
props: { |
|||
// icon name
|
|||
icon: propTypes.string, |
|||
// icon color
|
|||
color: propTypes.string, |
|||
// icon size
|
|||
size: { |
|||
type: [String, Number] as PropType<string | number>, |
|||
default: 16, |
|||
}, |
|||
prefix: propTypes.string.def(''), |
|||
}, |
|||
setup(props, { attrs }) { |
|||
const elRef = ref<ElRef>(null); |
|||
|
|||
const getIconRef = computed(() => { |
|||
const { icon, prefix } = props; |
|||
return `${prefix ? prefix + ':' : ''}${icon}`; |
|||
}); |
|||
|
|||
const update = async () => { |
|||
const el = unref(elRef); |
|||
if (el) { |
|||
await nextTick(); |
|||
const icon = unref(getIconRef); |
|||
|
|||
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); |
|||
} |
|||
} |
|||
}; |
|||
|
|||
const wrapStyleRef = computed( |
|||
(): CSSProperties => { |
|||
const { size, color } = props; |
|||
let fs = size; |
|||
if (isString(size)) { |
|||
fs = parseInt(size, 10); |
|||
} |
|||
return { |
|||
fontSize: `${fs}px`, |
|||
color, |
|||
display: 'inline-flex', |
|||
}; |
|||
} |
|||
); |
|||
|
|||
watch(() => props.icon, update, { flush: 'post' }); |
|||
|
|||
onMounted(update); |
|||
|
|||
return () => ( |
|||
<span ref={elRef} class={[attrs.class, 'app-iconify anticon']} style={unref(wrapStyleRef)} /> |
|||
); |
|||
}, |
|||
}); |
|||
@ -0,0 +1,100 @@ |
|||
<template> |
|||
<span ref="elRef" :class="[$attrs.class, 'app-iconify anticon']" :style="getWrapStyle" /> |
|||
</template> |
|||
<script lang="ts"> |
|||
import type { PropType } from 'vue'; |
|||
import { |
|||
defineComponent, |
|||
ref, |
|||
watch, |
|||
onMounted, |
|||
nextTick, |
|||
unref, |
|||
computed, |
|||
CSSProperties, |
|||
} from 'vue'; |
|||
import Iconify from '@purge-icons/generated'; |
|||
import { isString } from '/@/utils/is'; |
|||
import { propTypes } from '/@/utils/propTypes'; |
|||
export default defineComponent({ |
|||
name: 'GIcon', |
|||
props: { |
|||
// icon name |
|||
icon: propTypes.string, |
|||
// icon color |
|||
color: propTypes.string, |
|||
// icon size |
|||
size: { |
|||
type: [String, Number] as PropType<string | number>, |
|||
default: 16, |
|||
}, |
|||
prefix: propTypes.string.def(''), |
|||
}, |
|||
setup(props) { |
|||
const elRef = ref<ElRef>(null); |
|||
|
|||
const getIconRef = computed(() => { |
|||
const { icon, prefix } = props; |
|||
return `${prefix ? prefix + ':' : ''}${icon}`; |
|||
}); |
|||
|
|||
const update = async () => { |
|||
const el = unref(elRef); |
|||
if (el) { |
|||
await nextTick(); |
|||
const icon = unref(getIconRef); |
|||
|
|||
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); |
|||
} |
|||
} |
|||
}; |
|||
|
|||
const getWrapStyle = computed( |
|||
(): CSSProperties => { |
|||
const { size, color } = props; |
|||
let fs = size; |
|||
if (isString(size)) { |
|||
fs = parseInt(size, 10); |
|||
} |
|||
return { |
|||
fontSize: `${fs}px`, |
|||
color, |
|||
display: 'inline-flex', |
|||
}; |
|||
} |
|||
); |
|||
|
|||
watch(() => props.icon, update, { flush: 'post' }); |
|||
|
|||
onMounted(update); |
|||
|
|||
return { elRef, getWrapStyle }; |
|||
}, |
|||
}); |
|||
</script> |
|||
<style lang="less"> |
|||
@import (reference) '../../../design/index.less'; |
|||
|
|||
.app-iconify { |
|||
display: inline-block; |
|||
vertical-align: middle; |
|||
} |
|||
|
|||
span.iconify { |
|||
display: block; |
|||
min-width: 1em; |
|||
min-height: 1em; |
|||
background: @iconify-bg-color; |
|||
border-radius: 100%; |
|||
} |
|||
</style> |
|||
@ -1,9 +1,5 @@ |
|||
import './src/indicator'; |
|||
import { withInstall } from '../util'; |
|||
|
|||
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent'; |
|||
export const Loading = createAsyncComponent(() => import('./src/index.vue')); |
|||
|
|||
withInstall(Loading); |
|||
export { useLoading } from './src/useLoading'; |
|||
export { createLoading } from './src/createLoading'; |
|||
|
|||
@ -1,9 +0,0 @@ |
|||
// If you need to modify the default icon, you can open the comment and modify it here
|
|||
|
|||
// import { Spin } from 'ant-design-vue';
|
|||
// import { LoadingOutlined } from '@ant-design/icons-vue';
|
|||
// Spin.setDefaultIndicator({
|
|||
// indicator: () => {
|
|||
// return <LoadingOutlined spin />;
|
|||
// },
|
|||
// });
|
|||
@ -1,8 +1,4 @@ |
|||
import { withInstall } from '../util'; |
|||
|
|||
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent'; |
|||
export const MarkDown = createAsyncComponent(() => import('./src/index.vue')); |
|||
|
|||
withInstall(MarkDown); |
|||
|
|||
export * from './src/types'; |
|||
|
|||
@ -1,13 +1,5 @@ |
|||
import { withInstall } from '../util'; |
|||
|
|||
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent'; |
|||
|
|||
export const BasicMenu = createAsyncComponent(() => import('./src/BasicMenu.vue'), { |
|||
loading: false, |
|||
}); |
|||
|
|||
export const MenuTag = createAsyncComponent(() => import('./src/components/MenuItemTag.vue'), { |
|||
loading: false, |
|||
}); |
|||
export const BasicMenu = createAsyncComponent(() => import('./src/BasicMenu.vue')); |
|||
|
|||
withInstall(BasicMenu); |
|||
export const MenuTag = createAsyncComponent(() => import('./src/components/MenuItemTag.vue')); |
|||
|
|||
@ -1,11 +1,10 @@ |
|||
import './src/index.less'; |
|||
import { withInstall } from '../util'; |
|||
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent'; |
|||
|
|||
export const BasicModal = createAsyncComponent(() => import('./src/BasicModal')); |
|||
import BasicModal from './src/BasicModal'; |
|||
|
|||
withInstall(BasicModal); |
|||
|
|||
export { BasicModal }; |
|||
export { useModalContext } from './src/useModalContext'; |
|||
export { useModal, useModalInner } from './src/useModal'; |
|||
export * from './src/types'; |
|||
|
|||
@ -1,7 +1,4 @@ |
|||
import { withInstall } from '../util'; |
|||
|
|||
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent'; |
|||
export const QrCode = createAsyncComponent(() => import('./src/index.vue')); |
|||
|
|||
withInstall(QrCode); |
|||
export * from './src/types'; |
|||
|
|||
@ -1,7 +1,3 @@ |
|||
import { withInstall } from '../util'; |
|||
|
|||
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent'; |
|||
|
|||
export const StrengthMeter = createAsyncComponent(() => import('./src/index')); |
|||
|
|||
withInstall(StrengthMeter); |
|||
export const StrengthMeter = createAsyncComponent(() => import('./src/index.vue')); |
|||
@ -1,69 +0,0 @@ |
|||
@import (reference) '../../../design/index.less'; |
|||
|
|||
.strength-meter { |
|||
position: relative; |
|||
|
|||
&-bar { |
|||
position: relative; |
|||
height: 4px; |
|||
margin: 10px auto 6px; |
|||
background: @disabled-color; |
|||
border-radius: 3px; |
|||
|
|||
&::before, |
|||
&::after { |
|||
position: absolute; |
|||
z-index: 10; |
|||
display: block; |
|||
width: 20%; |
|||
height: inherit; |
|||
background: transparent; |
|||
border-color: @white; |
|||
border-style: solid; |
|||
border-width: 0 5px 0 5px; |
|||
content: ''; |
|||
} |
|||
|
|||
&::before { |
|||
left: 20%; |
|||
} |
|||
|
|||
&::after { |
|||
right: 20%; |
|||
} |
|||
|
|||
&__fill { |
|||
position: absolute; |
|||
width: 0; |
|||
height: inherit; |
|||
background: transparent; |
|||
border-radius: inherit; |
|||
transition: width 0.5s ease-in-out, background 0.25s; |
|||
|
|||
&[data-score='0'] { |
|||
width: 20%; |
|||
background: darken(@error-color, 10%); |
|||
} |
|||
|
|||
&[data-score='1'] { |
|||
width: 40%; |
|||
background: @error-color; |
|||
} |
|||
|
|||
&[data-score='2'] { |
|||
width: 60%; |
|||
background: @warning-color; |
|||
} |
|||
|
|||
&[data-score='3'] { |
|||
width: 80%; |
|||
background: fade(@success-color, 50%); |
|||
} |
|||
|
|||
&[data-score='4'] { |
|||
width: 100%; |
|||
background: @success-color; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,77 +0,0 @@ |
|||
import './index.less'; |
|||
|
|||
import { PropType } from 'vue'; |
|||
|
|||
import { defineComponent, computed, ref, watch, unref, watchEffect } from 'vue'; |
|||
|
|||
import { Input } from 'ant-design-vue'; |
|||
|
|||
import zxcvbn from 'zxcvbn'; |
|||
import { extendSlots } from '/@/utils/helper/tsxHelper'; |
|||
import { propTypes } from '/@/utils/propTypes'; |
|||
|
|||
const prefixCls = 'strength-meter'; |
|||
export default defineComponent({ |
|||
name: 'StrengthMeter', |
|||
props: { |
|||
value: propTypes.string, |
|||
|
|||
userInputs: { |
|||
type: Array as PropType<string[]>, |
|||
default: () => [], |
|||
}, |
|||
|
|||
showInput: propTypes.bool.def(true), |
|||
disabled: propTypes.bool, |
|||
}, |
|||
emits: ['score-change', 'change'], |
|||
setup(props, { emit, attrs, slots }) { |
|||
const innerValueRef = ref(''); |
|||
const getPasswordStrength = computed(() => { |
|||
const { userInputs, disabled } = props; |
|||
if (disabled) return null; |
|||
const innerValue = unref(innerValueRef); |
|||
const score = innerValue |
|||
? zxcvbn(unref(innerValueRef), (userInputs as string[]) || null).score |
|||
: null; |
|||
emit('score-change', score); |
|||
return score; |
|||
}); |
|||
|
|||
function handleChange(e: ChangeEvent) { |
|||
innerValueRef.value = e.target.value; |
|||
} |
|||
|
|||
watchEffect(() => { |
|||
innerValueRef.value = props.value || ''; |
|||
}); |
|||
watch( |
|||
() => unref(innerValueRef), |
|||
(val) => { |
|||
emit('change', val); |
|||
} |
|||
); |
|||
|
|||
return () => { |
|||
const { showInput, disabled } = props; |
|||
return ( |
|||
<div class={prefixCls}> |
|||
{showInput && ( |
|||
<Input.Password |
|||
{...attrs} |
|||
allowClear={true} |
|||
value={unref(innerValueRef)} |
|||
onChange={handleChange} |
|||
disabled={disabled} |
|||
> |
|||
{extendSlots(slots)} |
|||
</Input.Password> |
|||
)} |
|||
<div class={`${prefixCls}-bar`}> |
|||
<div class={`${prefixCls}-bar__fill`} data-score={unref(getPasswordStrength)}></div> |
|||
</div> |
|||
</div> |
|||
); |
|||
}; |
|||
}, |
|||
}); |
|||
@ -0,0 +1,156 @@ |
|||
<template> |
|||
<div :class="prefixCls"> |
|||
<InputPassword |
|||
v-if="showInput" |
|||
v-bind="$attrs" |
|||
allowClear |
|||
:value="innerValueRef" |
|||
@change="handleChange" |
|||
:disabled="disabled" |
|||
> |
|||
<template #[item]="data" v-for="item in Object.keys($slots)"> |
|||
<slot :name="item" v-bind="data" /> |
|||
</template> |
|||
</InputPassword> |
|||
<div :class="`${prefixCls}-bar`"> |
|||
<div :class="`${prefixCls}-bar--fill`" :data-score="getPasswordStrength"></div> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script lang="ts"> |
|||
import { PropType } from 'vue'; |
|||
|
|||
import { defineComponent, computed, ref, watch, unref, watchEffect } from 'vue'; |
|||
|
|||
import { Input } from 'ant-design-vue'; |
|||
|
|||
import zxcvbn from 'zxcvbn'; |
|||
import { propTypes } from '/@/utils/propTypes'; |
|||
import { useDesign } from '/@/hooks/web/useDesign'; |
|||
|
|||
export default defineComponent({ |
|||
name: 'StrengthMeter', |
|||
components: { InputPassword: Input.Password }, |
|||
props: { |
|||
value: propTypes.string, |
|||
|
|||
userInputs: { |
|||
type: Array as PropType<string[]>, |
|||
default: () => [], |
|||
}, |
|||
|
|||
showInput: propTypes.bool.def(true), |
|||
disabled: propTypes.bool, |
|||
}, |
|||
emits: ['score-change', 'change'], |
|||
setup(props, { emit }) { |
|||
const innerValueRef = ref(''); |
|||
const { prefixCls } = useDesign('strength-meter'); |
|||
|
|||
const getPasswordStrength = computed(() => { |
|||
const { userInputs, disabled } = props; |
|||
if (disabled) return null; |
|||
const innerValue = unref(innerValueRef); |
|||
const score = innerValue |
|||
? zxcvbn(unref(innerValueRef), (userInputs as string[]) || null).score |
|||
: null; |
|||
emit('score-change', score); |
|||
return score; |
|||
}); |
|||
|
|||
function handleChange(e: ChangeEvent) { |
|||
innerValueRef.value = e.target.value; |
|||
} |
|||
|
|||
watchEffect(() => { |
|||
innerValueRef.value = props.value || ''; |
|||
}); |
|||
watch( |
|||
() => unref(innerValueRef), |
|||
(val) => { |
|||
emit('change', val); |
|||
} |
|||
); |
|||
|
|||
return { |
|||
getPasswordStrength, |
|||
handleChange, |
|||
prefixCls, |
|||
innerValueRef, |
|||
}; |
|||
}, |
|||
}); |
|||
</script> |
|||
<style lang="less" scoped> |
|||
@import (reference) '../../../design/index.less'; |
|||
@prefix-cls: ~'@{namespace}-strength-meter'; |
|||
|
|||
.@{prefix-cls} { |
|||
position: relative; |
|||
|
|||
&-bar { |
|||
position: relative; |
|||
height: 4px; |
|||
margin: 10px auto 6px; |
|||
background: @disabled-color; |
|||
border-radius: 3px; |
|||
|
|||
&::before, |
|||
&::after { |
|||
position: absolute; |
|||
z-index: 10; |
|||
display: block; |
|||
width: 20%; |
|||
height: inherit; |
|||
background: transparent; |
|||
border-color: @white; |
|||
border-style: solid; |
|||
border-width: 0 5px 0 5px; |
|||
content: ''; |
|||
} |
|||
|
|||
&::before { |
|||
left: 20%; |
|||
} |
|||
|
|||
&::after { |
|||
right: 20%; |
|||
} |
|||
|
|||
&--fill { |
|||
position: absolute; |
|||
width: 0; |
|||
height: inherit; |
|||
background: transparent; |
|||
border-radius: inherit; |
|||
transition: width 0.5s ease-in-out, background 0.25s; |
|||
|
|||
&[data-score='0'] { |
|||
width: 20%; |
|||
background: darken(@error-color, 10%); |
|||
} |
|||
|
|||
&[data-score='1'] { |
|||
width: 40%; |
|||
background: @error-color; |
|||
} |
|||
|
|||
&[data-score='2'] { |
|||
width: 60%; |
|||
background: @warning-color; |
|||
} |
|||
|
|||
&[data-score='3'] { |
|||
width: 80%; |
|||
background: fade(@success-color, 50%); |
|||
} |
|||
|
|||
&[data-score='4'] { |
|||
width: 100%; |
|||
background: @success-color; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,9 +1,6 @@ |
|||
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent'; |
|||
import { withInstall } from '../util'; |
|||
|
|||
export const BasicTree = createAsyncComponent(() => import('./src/BasicTree')); |
|||
|
|||
withInstall(BasicTree); |
|||
|
|||
export type { ContextMenuItem } from '/@/hooks/web/useContextMenu'; |
|||
export * from './src/types'; |
|||
|
|||
@ -1,10 +1,6 @@ |
|||
import { withInstall } from '../util'; |
|||
|
|||
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent'; |
|||
|
|||
export const BasicDragVerify = createAsyncComponent(() => import('./src/DragVerify')); |
|||
export const RotateDragVerify = createAsyncComponent(() => import('./src/ImgRotate')); |
|||
|
|||
withInstall(BasicDragVerify, RotateDragVerify); |
|||
|
|||
export * from './src/types'; |
|||
|
|||
Loading…
Reference in new issue