version: v4.9.5

This commit is contained in:
XiaoDaiGua-Ray 2024-09-18 14:41:15 +08:00
parent 60ed09a0c5
commit d12fcd18b6
32 changed files with 949 additions and 618 deletions

View File

@ -1,5 +1,33 @@
# CHANGE LOG # CHANGE LOG
## 4.9.5
天元突破,红莲螺岩。
兼容 `vue3.5` 版本的更新。
## Feats
- 更新脚手架依赖为主流依赖
- 更新 `vue` 版本至 `3.5.6`
- 更新 `vite` 版本至 `5.4.3`
- 更新 `pinia-plugin-persistedstate` 版本至 `4.0.1`,并且兼容破坏性更新改动
- `RChart` 组件相关
- 小重构该组件,移除多个 `echart` 缓存,现在有且仅有一个
- 减少 `watch` 监听项
- 使用 `useTemplateRef` 方法替代 `ref` 注册 `dom`
- 现在预设 `card` 时,`chart` 图会更加的醒目一些
- 优化 `demo` 展示
- 现在会拦截 `aria` 属性,现在仅允许通过 `showAria` 配置项管理无障碍模式
- 优化无障碍模式渲染,现在不会重新渲染整个图表,而是通过 `setOptions` 方式更新图表
- `useChart` 方法相关
- `isDispose` 方法更名为 `isDisposed`
## Fixes
- 修复 `useChart` 方法相关方法中 `dispose` 方法执行不生效的问题
- 修复 `RChart``loading` 不能跟随主题变化的问题
## 4.9.4 ## 4.9.4
## Feats ## Feats

View File

@ -1,7 +1,7 @@
{ {
"name": "ray-template", "name": "ray-template",
"private": false, "private": false,
"version": "4.9.4", "version": "4.9.5",
"type": "module", "type": "module",
"engines": { "engines": {
"node": "^18.0.0 || >=20.0.0", "node": "^18.0.0 || >=20.0.0",
@ -46,9 +46,9 @@
"mockjs": "1.1.0", "mockjs": "1.1.0",
"naive-ui": "^2.39.0", "naive-ui": "^2.39.0",
"pinia": "^2.1.7", "pinia": "^2.1.7",
"pinia-plugin-persistedstate": "^3.2.0", "pinia-plugin-persistedstate": "^4.0.1",
"print-js": "^1.6.0", "print-js": "^1.6.0",
"vue": "^3.4.38", "vue": "^3.5.6",
"vue-demi": "0.14.6", "vue-demi": "0.14.6",
"vue-hooks-plus": "2.2.1", "vue-hooks-plus": "2.2.1",
"vue-i18n": "^9.13.1", "vue-i18n": "^9.13.1",
@ -56,26 +56,26 @@
"vue3-next-qrcode": "2.0.10" "vue3-next-qrcode": "2.0.10"
}, },
"devDependencies": { "devDependencies": {
"@commitlint/cli": "^17.7.1", "@commitlint/cli": "^17.8.1",
"@commitlint/config-conventional": "^17.7.0", "@commitlint/config-conventional": "^17.8.1",
"@interactjs/types": "1.10.21", "@interactjs/types": "1.10.21",
"@intlify/unplugin-vue-i18n": "^4.0.0", "@intlify/unplugin-vue-i18n": "^4.0.0",
"@types/crypto-js": "^4.1.1", "@types/crypto-js": "^4.2.2",
"@types/dom-to-image": "2.6.7", "@types/dom-to-image": "2.6.7",
"@types/jsbarcode": "3.11.4", "@types/jsbarcode": "3.11.4",
"@types/lodash-es": "^4.17.12", "@types/lodash-es": "^4.17.12",
"@types/mockjs": "1.0.7", "@types/mockjs": "1.0.7",
"@typescript-eslint/eslint-plugin": "^6.5.0", "@typescript-eslint/eslint-plugin": "^6.21.0",
"@typescript-eslint/parser": "^6.5.0", "@typescript-eslint/parser": "^6.21.0",
"@vitejs/plugin-vue": "^5.1.0", "@vitejs/plugin-vue": "^5.1.0",
"@vitejs/plugin-vue-jsx": "^4.0.0", "@vitejs/plugin-vue-jsx": "^4.0.0",
"@vitest/ui": "1.4.0", "@vitest/ui": "1.4.0",
"@vue/eslint-config-prettier": "^9.0.0", "@vue/eslint-config-prettier": "^9.0.0",
"@vue/eslint-config-typescript": "^12.0.0", "@vue/eslint-config-typescript": "^12.0.0",
"@vue/test-utils": "2.4.3", "@vue/test-utils": "2.4.3",
"autoprefixer": "^10.4.15", "autoprefixer": "^10.4.16",
"depcheck": "^1.4.5", "depcheck": "^1.4.7",
"eslint": "^8.56.0", "eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0", "eslint-config-prettier": "^9.1.0",
"eslint-config-standard-with-typescript": "^43.0.0", "eslint-config-standard-with-typescript": "^43.0.0",
"eslint-plugin-prettier": "^5.1.3", "eslint-plugin-prettier": "^5.1.3",
@ -83,16 +83,16 @@
"eslint-plugin-vue": "^9.25.0", "eslint-plugin-vue": "^9.25.0",
"happy-dom": "14.3.1", "happy-dom": "14.3.1",
"husky": "8.0.3", "husky": "8.0.3",
"lint-staged": "^15.1.0", "lint-staged": "^15.2.0",
"postcss": "^8.4.31", "postcss": "^8.4.38",
"postcss-px-to-viewport-8-with-include": "1.2.2", "postcss-px-to-viewport-8-with-include": "1.2.2",
"prettier": "^3.2.5", "prettier": "^3.2.5",
"sass": "1.71.1", "sass": "1.71.1",
"svg-sprite-loader": "^6.0.11", "svg-sprite-loader": "^6.0.11",
"typescript": "^5.2.2", "typescript": "^5.2.2",
"unplugin-auto-import": "^0.17.5", "unplugin-auto-import": "^0.18.2",
"unplugin-vue-components": "^0.26.0", "unplugin-vue-components": "^0.27.4",
"vite": "^5.4.1", "vite": "^5.4.3",
"vite-bundle-analyzer": "0.9.4", "vite-bundle-analyzer": "0.9.4",
"vite-plugin-cdn2": "1.1.0", "vite-plugin-cdn2": "1.1.0",
"vite-plugin-compression": "^0.5.1", "vite-plugin-compression": "^0.5.1",
@ -104,7 +104,7 @@
"vite-svg-loader": "^4.0.0", "vite-svg-loader": "^4.0.0",
"vite-tsconfig-paths": "4.3.2", "vite-tsconfig-paths": "4.3.2",
"vitest": "1.5.2", "vitest": "1.5.2",
"vue-tsc": "^2.0.11" "vue-tsc": "^2.0.13"
}, },
"description": "<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->", "description": "<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->",
"main": "index.ts", "main": "index.ts",

934
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -31,6 +31,8 @@ import { NSpin } from 'naive-ui'
import { spinProps } from 'naive-ui' import { spinProps } from 'naive-ui'
import { getVariableToRefs } from '@/global-variable' import { getVariableToRefs } from '@/global-variable'
import type { SpinProps } from 'naive-ui'
const GlobalSpin = defineComponent({ const GlobalSpin = defineComponent({
name: 'GlobalSpin', name: 'GlobalSpin',
props: { props: {
@ -50,7 +52,7 @@ const GlobalSpin = defineComponent({
render() { render() {
return ( return (
<NSpin <NSpin
{...this.$props} {...(this.$props as SpinProps)}
show={this.spinValue} show={this.spinValue}
themeOverrides={this.overrides} themeOverrides={this.overrides}
> >

View File

@ -13,6 +13,8 @@ import { RCollapseGrid, RForm } from '@/components'
import { collapseGridProps, formProps } from '@/components' import { collapseGridProps, formProps } from '@/components'
import type { FormProps, GridProps } from 'naive-ui'
/** /**
* *
* @description * @description
@ -38,7 +40,8 @@ export default defineComponent({
), ),
render() { render() {
const { $slots, $props } = this const { $slots, $props } = this
const { labelPlacement, showFeedback, ...rest } = $props const { labelPlacement, showFeedback, ...rest } = $props as FormProps &
GridProps
return ( return (
<RForm {...rest} labelPlacement="top" showFeedback={false}> <RForm {...rest} labelPlacement="top" showFeedback={false}>

View File

@ -17,7 +17,6 @@ import { call } from '@/utils'
import { usePagination } from '@/hooks' import { usePagination } from '@/hooks'
import type { TablePagination, TableRequestConfig, TableProInst } from './types' import type { TablePagination, TableRequestConfig, TableProInst } from './types'
import type { Recordable } from '@/types'
export default defineComponent({ export default defineComponent({
name: 'RTablePro', name: 'RTablePro',
@ -162,7 +161,9 @@ export default defineComponent({
}, },
render() { render() {
const { register, $props, paginationRef, $slots } = this const { register, $props, paginationRef, $slots } = this
const { onRegister, showPagination, ...rest } = $props const { onRegister, showPagination, ...rest } = $props as ExtractPropTypes<
typeof props
>
return ( return (
<RTable <RTable

View File

@ -16,6 +16,7 @@ import { NSpin } from 'naive-ui'
import barcode from 'jsbarcode' import barcode from 'jsbarcode'
import props from './props' import props from './props'
import { completeSize, call } from '@/utils' import { completeSize, call } from '@/utils'
import { useTemplateRef } from 'vue'
import type { WatchStopHandle } from 'vue' import type { WatchStopHandle } from 'vue'
@ -23,7 +24,9 @@ export default defineComponent({
name: 'RBarcode', name: 'RBarcode',
props, props,
setup(props) { setup(props) {
const barcodeRef = ref<HTMLCanvasElement | HTMLOrSVGElement>() const barcodeRef = useTemplateRef<HTMLCanvasElement | HTMLOrSVGElement>(
'barcodeRef',
)
const cssVars = computed(() => { const cssVars = computed(() => {
const cssVar = { const cssVar = {
'--r-barcode-width': completeSize(props.width), '--r-barcode-width': completeSize(props.width),

View File

@ -79,10 +79,9 @@ const useChart = () => {
* *
* @description * @description
* chart * chart
* true, false * true false
*/ */
const isDispose = () => const isDisposed = () => !!getChartInstance().echartInst?.isDisposed()
!(echartInst && getChartInstance().echartInst.getDom())
/** /**
* *
@ -102,7 +101,7 @@ const useChart = () => {
register, register,
{ {
getChartInstance, getChartInstance,
isDispose, isDisposed,
dispose, dispose,
render, render,
}, },

View File

@ -26,7 +26,7 @@ import { NCard } from 'naive-ui'
import props from './props' import props from './props'
import { throttle } from 'lodash-es' import { throttle } from 'lodash-es'
import { completeSize, downloadBase64File, call, renderNode } from '@/utils' import { completeSize, downloadBase64File, call, renderNode } from '@/utils'
import { setupChartTheme } from './utils' import { getCustomEchartTheme, loadingOptions, setEchartOptions } from './utils'
import { APP_THEME } from '@/app-config' import { APP_THEME } from '@/app-config'
import { import {
useResizeObserver, useResizeObserver,
@ -35,6 +35,7 @@ import {
} from '@vueuse/core' } from '@vueuse/core'
import { RMoreDropdown } from '@/components' import { RMoreDropdown } from '@/components'
import { useSettingGetters } from '@/store' import { useSettingGetters } from '@/store'
import { useTemplateRef } from 'vue'
import type { WatchStopHandle } from 'vue' import type { WatchStopHandle } from 'vue'
import type { AnyFC } from '@/types' import type { AnyFC } from '@/types'
@ -46,15 +47,8 @@ import type {
import type { ECharts, EChartsCoreOption } from 'echarts/core' import type { ECharts, EChartsCoreOption } from 'echarts/core'
import type { DropdownProps, DropdownOption } from 'naive-ui' import type { DropdownProps, DropdownOption } from 'naive-ui'
// setOption 默认配置项
const defaultChartOptions = {
notMerge: true,
lazyUpdate: true,
silent: false,
replaceMerge: [],
}
// 获取 chart 主题 // 获取 chart 主题
const echartThemes = setupChartTheme() const echartThemes = getCustomEchartTheme()
// download 下载功能 key // download 下载功能 key
const __CHART_DOWN_LOAD_CHART__ = '__R_CHART_DOWN_LOAD_CHART__' const __CHART_DOWN_LOAD_CHART__ = '__R_CHART_DOWN_LOAD_CHART__'
@ -92,14 +86,21 @@ export default defineComponent({
props, props,
setup(props, { expose }) { setup(props, { expose }) {
const { getAppTheme } = useSettingGetters() const { getAppTheme } = useSettingGetters()
const rayChartRef = ref<HTMLElement>() // echart 容器实例 // echart 容器实例
const rayChartWrapperRef = ref<HTMLElement>() // echart 父容器实例 const rayChartRef = useTemplateRef<HTMLElement>('rayChartRef')
const echartInstanceRef = ref<ECharts>() // echart 实例 // echart 父容器实例
let resizeThrottleReturn: DebouncedFunc<AnyFC> | null // resize 防抖方法实例 const rayChartWrapperRef = useTemplateRef<HTMLElement>('rayChartWrapperRef')
let resizeObserverReturn: UseResizeObserverReturn | null // resize observer 实例 // echart 实例
const { echartTheme } = APP_THEME // 当前配置主题 const echartInstanceRef = shallowRef<ECharts>()
let watchThrottledCallback: WatchStopHandle | null // watch props 回调 // resize 防抖方法实例
let echartInst: ECharts | null // 无代理响应式代理缓存 echart inst let resizeThrottleReturn: DebouncedFunc<AnyFC> | null
// resize observer 实例
let resizeObserverReturn: UseResizeObserverReturn | null
// 当前配置主题
const { echartTheme } = APP_THEME
// watch props 回调
let watchThrottledCallback: WatchStopHandle | null
// 下拉框配置项
const moreDropDownOptions = computed<DropdownProps['options']>(() => [ const moreDropDownOptions = computed<DropdownProps['options']>(() => [
{ {
label: '下载图片', label: '下载图片',
@ -108,22 +109,29 @@ export default defineComponent({
echartInstanceRef.value && echartInstanceRef.value.getDom() echartInstanceRef.value && echartInstanceRef.value.getDom()
), ),
}, },
]) // 下拉框配置项 ])
const cssVarsRef = computed(() => { const cssVarsRef = computed(() => {
return { return {
'--ray-chart-width': completeSize(props.width), '--ray-chart-width': completeSize(props.width),
'--ray-chart-height': completeSize(props.height), '--ray-chart-height': completeSize(props.height),
} }
}) })
const targetIsVisible = ref(false) // 目标是否可见 // 目标是否可见
let intersectionObserverReturn: UseIntersectionObserverReturn | null // intersectionObserver 实例 const targetIsVisible = ref(false)
// intersectionObserver 实例
let intersectionObserverReturn: UseIntersectionObserverReturn | null
// 缓存一些配置信息
const __catch = {
aria: props.showAria,
}
/** /**
* *
* `echart` , , * @description
* echart
* *
* `echart` * echart
* *
*/ */
const registerChartCore = async () => { const registerChartCore = async () => {
use([ use([
@ -156,16 +164,17 @@ export default defineComponent({
/** /**
* *
* chart * @description
* chart
* *
* theme autoChangeTheme * theme autoChangeTheme
* theme default chart * theme default chart
* *
* Boolean(theme) false echartTheme * Boolean(theme) false echartTheme
* echartTheme 使 * echartTheme 使
*/ */
const updateChartTheme = () => { const updateChartTheme = () => {
if (echartInst?.getDom()) { if (echartInstanceRef.value) {
destroyChart() destroyChart()
} }
@ -199,66 +208,61 @@ export default defineComponent({
*/ */
const combineChartOptions = (ops: EChartsCoreOption) => { const combineChartOptions = (ops: EChartsCoreOption) => {
let options = unref(ops) let options = unref(ops)
const assign = (opts: object) => Object.assign({}, options, opts) const assign = (opts: object) => Object.assign({}, options, opts)
if (props.showAria) { // 拦截 aria 配置项
options = assign({ options = assign({
aria: { aria: {
enabled: true, enabled: props.showAria,
decal: { decal: {
show: true, show: props.showAria,
}, },
}, },
}) })
}
return options return options
} }
/** /**
* *
* `echart` * @description
* * echart
*
* 使, `legend`
*/ */
const renderChart = (theme: string = echartTheme) => { const renderChart = (theme: string = echartTheme) => {
/** 获取 dom 容器 */ // 获取 dom 容器
const element = rayChartRef.value as HTMLElement const element = rayChartRef.value as HTMLElement
/** 获取配置项 */ // 获取配置项
const options = combineChartOptions(props.options) const options = combineChartOptions(props.options)
/** 获取 dom 容器实际宽高 */ // 获取 dom 容器实际宽高
const { height, width } = element.getBoundingClientRect() const { height, width } = element.getBoundingClientRect()
const { onSuccess, onError } = props const { onSuccess, onError } = props
try { try {
/** 注册 chart */ // 注册 chart
echartInst = init(element, theme, { echartInstanceRef.value = init(element, theme, {
/** 如果款度为 0, 则以 200px 填充 */ // 如果款度为 0则以 200px 填充
width: width === 0 ? 200 : void 0, width: width === 0 ? 200 : void 0,
/** 如果高度为 0, 则以 200px 填充 */ // 如果高度为 0则以 200px 填充
height: height === 0 ? 200 : void 0, height: height === 0 ? 200 : void 0,
}) })
echartInstanceRef.value = echartInst
// 渲染成功回调 // 渲染成功回调
if (onSuccess) { if (onSuccess) {
call(onSuccess, echartInst) call(onSuccess, echartInstanceRef.value)
} }
// 是否强制下一队列渲染图表 // 是否强制下一队列渲染图表
if (props.nextTick) { if (props.nextTick) {
echartInst.setOption({}) echartInstanceRef.value.setOption({})
nextTick(() => { nextTick(() => {
options && echartInst?.setOption(options) options && echartInstanceRef.value?.setOption(options)
}) })
} else { } else {
options && echartInst?.setOption(options) options && echartInstanceRef.value?.setOption(options)
} }
} catch (e) { } catch (e) {
/** 渲染失败回调 */ // 渲染失败回调
if (onError) { if (onError) {
call(onError) call(onError)
} }
@ -279,26 +283,29 @@ export default defineComponent({
* chart * chart
* true, false * true, false
*/ */
const isDispose = () => !(echartInst && echartInst.getDom()) const isDisposed = () => {
return !!echartInstanceRef.value?.isDisposed()
}
/** /**
* *
* chart , * @description
* chart
*/ */
const destroyChart = () => { const destroyChart = () => {
if (!isDispose()) { if (!isDisposed()) {
echartInst!.clear() echartInstanceRef.value?.dispose()
echartInst!.dispose()
echartInstanceRef.value = void 0
echartInst = null
} }
} }
/** 重置 echarts 尺寸 */ /**
*
* @description
* echarts
*/
const resizeChart = () => { const resizeChart = () => {
if (echartInst) { if (echartInstanceRef.value) {
echartInst.resize() echartInstanceRef.value.resize()
} }
} }
@ -307,15 +314,16 @@ export default defineComponent({
* @param key moreDropDownOptions key * @param key moreDropDownOptions key
* @param option moreDropDownOptions current click option * @param option moreDropDownOptions current click option
* *
* card * @description
* * card
*
*/ */
const dropdownSelect = (key: string | number, option: DropdownOption) => { const dropdownSelect = (key: string | number, option: DropdownOption) => {
if (key === __CHART_DOWN_LOAD_CHART__ && !isDispose()) { if (key === __CHART_DOWN_LOAD_CHART__ && !isDisposed()) {
const { filename, ...args } = props.downloadOptions const { filename, ...args } = props.downloadOptions
downloadBase64File( downloadBase64File(
echartInst!.getDataURL(args), echartInstanceRef.value!.getDataURL(args),
filename ?? `${new Date().getTime()}`, filename ?? `${new Date().getTime()}`,
) )
} }
@ -327,6 +335,11 @@ export default defineComponent({
} }
} }
/**
*
* @description
* chart
*/
const mount = () => { const mount = () => {
// 注册事件 // 注册事件
if (props.autoResize) { if (props.autoResize) {
@ -348,7 +361,7 @@ export default defineComponent({
} }
// 避免重复渲染 // 避免重复渲染
if (echartInst?.getDom()) { if (echartInstanceRef.value?.getDom()) {
return return
} }
@ -357,7 +370,7 @@ export default defineComponent({
return return
} }
// 渲染 chart // 根据主题渲染 chart
updateChartTheme() updateChartTheme()
// 初始化完成后移除 intersectionObserver 监听 // 初始化完成后移除 intersectionObserver 监听
@ -366,21 +379,16 @@ export default defineComponent({
// 注册 register用于 useChart hook // 注册 register用于 useChart hook
const { onRegister } = props const { onRegister } = props
if (onRegister && echartInst) { if (onRegister && echartInstanceRef.value) {
call(onRegister, echartInst, mount, unmount) call(onRegister, echartInstanceRef.value, mount, unmount)
} }
} }
if (props.intersectionObserver) { /**
intersectionObserverReturn = useIntersectionObserver( *
props.intersectionObserverTarget || rayChartWrapperRef, * @description
([entry]) => { * chart
targetIsVisible.value = entry.isIntersecting */
},
props.intersectionOptions,
)
}
const unmount = () => { const unmount = () => {
// 卸载 echarts // 卸载 echarts
destroyChart() destroyChart()
@ -395,15 +403,17 @@ export default defineComponent({
resizeObserverReturn = null resizeObserverReturn = null
} }
/** 监听全局主题变化, 然后重新渲染对应主题 echarts */ // 监听全局主题变化,然后重新渲染对应主题 echarts
watch( watch(
() => getAppTheme.value, () => getAppTheme.value,
() => { () => {
/** /**
* *
* Q: 为什么需要重新卸载再渲染 * @description
* A: 因为 echarts * Q: 为什么需要重新卸载再渲染
* A: 虽然原型上有 setTheme , ECharts 访 * A: 因为 echarts
* setTheme ECharts 访
*
*/ */
if (props.autoChangeTheme) { if (props.autoChangeTheme) {
destroyChart() destroyChart()
@ -411,21 +421,19 @@ export default defineComponent({
} }
}, },
) )
/**
*
*
*
*
*/
watch(
() => props.showAria,
() => {
destroyChart()
updateChartTheme()
},
)
watchEffect(() => { watchEffect(() => {
/** 监听 options 变化 */ // 是否启用了可视区域监听
if (props.intersectionObserver) {
intersectionObserverReturn = useIntersectionObserver(
props.intersectionObserverTarget || rayChartWrapperRef,
([entry]) => {
targetIsVisible.value = entry.isIntersecting
},
props.intersectionOptions,
)
}
// 监听 options 变化
if (props.watchOptions) { if (props.watchOptions) {
watchThrottledCallback = watchThrottled( watchThrottledCallback = watchThrottled(
() => props.options, () => props.options,
@ -434,12 +442,12 @@ export default defineComponent({
const options = combineChartOptions(ndata) const options = combineChartOptions(ndata)
const setOpt = Object.assign( const setOpt = Object.assign(
{}, {},
defaultChartOptions, setEchartOptions(),
props.setChartOptions, props.setChartOptions,
) )
// 如果 options 发生变动更新 echarts // 如果 options 发生变动更新 echarts
echartInst?.setOption(options, setOpt) echartInstanceRef.value?.setOption(options, setOpt)
}, },
{ {
// 深度监听 options // 深度监听 options
@ -453,11 +461,20 @@ export default defineComponent({
// 监听 loading 变化 // 监听 loading 变化
props.loading props.loading
? echartInst?.showLoading(props.loadingOptions) ? echartInstanceRef.value?.showLoading(
: echartInst?.hideLoading() loadingOptions(props.loadingOptions),
)
: echartInstanceRef.value?.hideLoading()
// 贴花是否启用
if (props.showAria !== __catch.aria && echartInstanceRef.value) {
echartInstanceRef.value.setOption(combineChartOptions(props.options))
__catch.aria = props.showAria
}
// 当前图表容器是否处于可见状态,如果可见则渲染图表 // 当前图表容器是否处于可见状态,如果可见则渲染图表
if (targetIsVisible.value) { if (targetIsVisible.value && !isDisposed()) {
mount() mount()
} }
}) })
@ -504,6 +521,7 @@ export default defineComponent({
style={[this.cssVarsRef]} style={[this.cssVarsRef]}
contentStyle={contentStyle} contentStyle={contentStyle}
bordered={bordered} bordered={bordered}
embedded
> >
{{ {{
default: renderNode( default: renderNode(
@ -517,7 +535,7 @@ export default defineComponent({
<RMoreDropdown <RMoreDropdown
iconSize={18} iconSize={18}
cursor="pointer" cursor="pointer"
options={dropdownOptions ?? moreDropDownOptions} options={dropdownOptions || moreDropDownOptions}
trigger="click" trigger="click"
onSelect={dropdownSelect.bind(this)} onSelect={dropdownSelect.bind(this)}
placement="bottom-end" placement="bottom-end"

View File

@ -1,4 +1,4 @@
import { loadingOptions } from './utils' import { loadingOptions, setEchartOptions } from './utils'
import type * as echarts from 'echarts/core' // echarts 核心模块 import type * as echarts from 'echarts/core' // echarts 核心模块
import type { PropType, VNode } from 'vue' import type { PropType, VNode } from 'vue'
@ -192,7 +192,8 @@ const props = {
* *
* @description * @description
* chart * chart
* options aria * aria enabled decal.show
* options
* *
* @default false * @default false
*/ */
@ -344,6 +345,7 @@ const props = {
* *
* @description * @description
* *
*
* *
* @default true * @default true
*/ */
@ -360,12 +362,7 @@ const props = {
*/ */
setChartOptions: { setChartOptions: {
type: Object as PropType<SetOptionOpts>, type: Object as PropType<SetOptionOpts>,
default: () => ({ default: () => setEchartOptions(),
notMerge: true,
lazyUpdate: true,
silent: false,
replaceMerge: [],
}),
}, },
/** /**
* *

View File

@ -1,95 +0,0 @@
/**
*
* @author Ray <https://github.com/XiaoDaiGua-Ray>
*
* @date 2023-07-22
*
* @workspace ray-template
*
* @remark
*/
import { useTheme } from '@/hooks'
import type {
ChartThemeRawArray,
ChartThemeRawModules,
LoadingOptions,
} from '@/components/RChart/src/types'
/**
*
* @see https://echarts.apache.org/zh/theme-builder.html
*
* @description
*
*
*
*
* 使:
* 1.
* 2.
* 3. json
* 4. echart-themes json
*/
export const setupChartTheme = () => {
// 获取所有主题
const themeRawModules: Record<string, ChartThemeRawModules> =
import.meta.glob('@/app-config/echart-themes/**/*.json', {
eager: true,
})
const regex = /\/([^/]+)\.json$/
const rawThemes = Object.keys(themeRawModules).reduce((pre, curr) => {
const name = curr.match(regex)?.[1]
if (name) {
pre.push({
name,
theme: themeRawModules[curr].default,
})
return pre
} else {
throw new Error(`[RChart Theme Error]: name ${curr} is invalid!`)
}
}, [] as ChartThemeRawArray[])
return rawThemes
}
/**
*
* @param options
*
* @description
* chart
*
* @see https://echarts.apache.org/zh/api.html#echartsInstance.showLoading
*
* @example
* const options = loadingOptions({ ...LoadingOptions })
*/
export const loadingOptions = (options?: LoadingOptions) => {
const { getAppTheme } = useTheme()
const { theme } = getAppTheme()
return Object.assign(
{},
{
text: 'loading',
color: '#c23531',
textColor: theme ? '#fff' : '#000',
maskColor: theme ? 'rgba(0, 0, 0, 0.5)' : 'rgba(255, 255, 255, 0.5)',
zlevel: 0,
fontSize: 12,
showSpinner: true,
spinnerRadius: 10,
lineWidth: 5,
fontWeight: 'normal',
fontStyle: 'normal',
fontFamily: 'sans-serif',
},
options,
)
}

View File

@ -0,0 +1,45 @@
import type {
ChartThemeRawArray,
ChartThemeRawModules,
} from '@/components/RChart/src/types'
/**
*
* @see https://echarts.apache.org/zh/theme-builder.html
*
* @description
*
*
*
*
* 使:
* 1.
* 2.
* 3. json
* 4. echart-themes json
*/
export const getCustomEchartTheme = () => {
// 获取所有主题
const themeRawModules: Record<string, ChartThemeRawModules> =
import.meta.glob('@/app-config/echart-themes/**/*.json', {
eager: true,
})
const regex = /\/([^/]+)\.json$/
const rawThemes = Object.keys(themeRawModules).reduce((pre, curr) => {
const name = curr.match(regex)?.[1]
if (name) {
pre.push({
name,
theme: themeRawModules[curr].default,
})
return pre
} else {
throw new Error(`[RChart Theme Error]: name ${curr} is invalid!`)
}
}, [] as ChartThemeRawArray[])
return rawThemes
}

View File

@ -0,0 +1,3 @@
export { getCustomEchartTheme } from './get-custom-echart-theme'
export { loadingOptions } from './loading-options'
export { setEchartOptions } from './set-echart-options'

View File

@ -0,0 +1,35 @@
import { useTheme } from '@/hooks'
import type { LoadingOptions } from '@/components/RChart/src/types'
/**
*
* @param options
*
* @description
* chart
*
* @see https://echarts.apache.org/zh/api.html#echartsInstance.showLoading
*
* @example
* const options = loadingOptions({ ...LoadingOptions })
*/
export const loadingOptions = (options?: LoadingOptions) => {
const { getAppTheme } = useTheme()
const { theme } = getAppTheme()
return Object.assign({}, options, {
text: 'loading',
color: '#c23531',
textColor: theme ? '#fff' : '#000',
maskColor: theme ? 'rgba(0, 0, 0, 0.8)' : 'rgba(255, 255, 255, 0.8)',
zlevel: 0,
fontSize: 12,
showSpinner: true,
spinnerRadius: 10,
lineWidth: 5,
fontWeight: 'normal',
fontStyle: 'normal',
fontFamily: 'sans-serif',
})
}

View File

@ -0,0 +1,13 @@
/**
*
* @see https://echarts.apache.org/zh/api.html#echartsInstance.setOption
*
* @description
* setOptions
*/
export const setEchartOptions = () => ({
notMerge: true,
lazyUpdate: true,
silent: false,
replaceMerge: [],
})

View File

@ -27,6 +27,8 @@ import { RIcon } from '@/components'
import { call } from '@/utils' import { call } from '@/utils'
import props from './props' import props from './props'
import type { GridProps } from 'naive-ui'
export default defineComponent({ export default defineComponent({
name: 'RCollapseGrid', name: 'RCollapseGrid',
props, props,
@ -99,7 +101,7 @@ export default defineComponent({
default: () => ( default: () => (
<NGrid <NGrid
class="ray-collapse-grid" class="ray-collapse-grid"
{...$props} {...($props as GridProps)}
collapsed={modelCollapsed} collapsed={modelCollapsed}
xGap={xGap || 12} xGap={xGap || 12}
yGap={yGap || 12} yGap={yGap || 12}

View File

@ -13,14 +13,16 @@ import { NForm } from 'naive-ui'
import props from './props' import props from './props'
import { call } from '@/utils' import { call } from '@/utils'
import { useTemplateRef } from 'vue'
import type { RFormInst } from './types' import type { RFormInst } from './types'
import type { FormProps } from 'naive-ui'
export default defineComponent({ export default defineComponent({
name: 'RForm', name: 'RForm',
props, props,
setup(props, { expose }) { setup(props, { expose }) {
const formRef = ref<RFormInst>() const formRef = useTemplateRef<RFormInst>('formRef')
onMounted(() => { onMounted(() => {
// 主动调用 register 方法,满足 useForm 方法正常调用 // 主动调用 register 方法,满足 useForm 方法正常调用
@ -41,7 +43,7 @@ export default defineComponent({
const { $attrs, $props, $slots } = this const { $attrs, $props, $slots } = this
return ( return (
<NForm {...$attrs} {...$props} ref="formRef"> <NForm {...$attrs} {...($props as FormProps)} ref="formRef">
{{ {{
...$slots, ...$slots,
}} }}

View File

@ -16,6 +16,7 @@ import { NSpin } from 'naive-ui'
import { call, completeSize } from '@/utils' import { call, completeSize } from '@/utils'
import props from './props' import props from './props'
import { useEventListener } from '@vueuse/core' import { useEventListener } from '@vueuse/core'
import { useTemplateRef } from 'vue'
export default defineComponent({ export default defineComponent({
name: 'RIframe', name: 'RIframe',
@ -30,7 +31,7 @@ export default defineComponent({
return cssVar return cssVar
}) })
const iframeRef = ref<HTMLIFrameElement>() const iframeRef = useTemplateRef<HTMLIFrameElement>('iframeRef')
const spinShow = ref(true) const spinShow = ref(true)
const iframeLoadSuccess = (e: Event) => { const iframeLoadSuccess = (e: Event) => {
@ -83,9 +84,7 @@ export default defineComponent({
allow={this.allow} allow={this.allow}
name={this.name} name={this.name}
title={this.title} title={this.title}
{...{ loading={typeof this.lazy === 'boolean' ? 'lazy' : this.lazy}
loading: this.lazy ? 'lazy' : null,
}}
/> />
), ),
}} }}

View File

@ -12,6 +12,7 @@
import type { PropType } from 'vue' import type { PropType } from 'vue'
import type { MaybeArray } from '@/types' import type { MaybeArray } from '@/types'
import type { SpinProps } from 'naive-ui' import type { SpinProps } from 'naive-ui'
import type { Lazy } from './types'
const props = { const props = {
src: { src: {
@ -90,7 +91,7 @@ const props = {
}, },
lazy: { lazy: {
/** 是否延迟加载 iframe */ /** 是否延迟加载 iframe */
type: Boolean, type: [Boolean, String] as PropType<boolean | Lazy>,
default: true, default: true,
}, },
iframeClass: { iframeClass: {

View File

@ -12,3 +12,5 @@
export interface RIframeInst { export interface RIframeInst {
iframe: Ref<HTMLIFrameElement> iframe: Ref<HTMLIFrameElement>
} }
export type Lazy = 'lazy' | 'eager' | undefined

View File

@ -23,6 +23,7 @@ import {
} from './constant' } from './constant'
import type interact from 'interactjs' import type interact from 'interactjs'
import type { ModalProps } from 'naive-ui'
export default defineComponent({ export default defineComponent({
name: 'RModal', name: 'RModal',
@ -93,7 +94,7 @@ export default defineComponent({
}, },
render() { render() {
const { $props, $slots, $attrs } = this const { $props, $slots, $attrs } = this
const { preset, ...$otherProps } = $props const { preset, ...$otherProps } = $props as ModalProps
const { cssVars, uuidEl, isFullscreenCardType } = this const { cssVars, uuidEl, isFullscreenCardType } = this
return ( return (

View File

@ -15,6 +15,8 @@ import { RIcon } from '@/components'
import props from './props' import props from './props'
import { renderNode } from '@/utils' import { renderNode } from '@/utils'
import type { DropdownProps } from 'naive-ui'
export default defineComponent({ export default defineComponent({
name: 'RMoreDropdown', name: 'RMoreDropdown',
props, props,
@ -23,7 +25,11 @@ export default defineComponent({
const { default: $default } = this.$slots const { default: $default } = this.$slots
return ( return (
<NDropdown {...this.$props} {...this.$attrs} placement="bottom-start"> <NDropdown
{...(this.$props as DropdownProps)}
{...this.$attrs}
placement="bottom-start"
>
{renderNode($default, { {renderNode($default, {
defaultElement: <RIcon name={icon} size={iconSize} cursor={cursor} />, defaultElement: <RIcon name={icon} size={iconSize} cursor={cursor} />,
})} })}

View File

@ -22,8 +22,9 @@ import props from './props'
import { call, renderNode, uuid } from '@/utils' import { call, renderNode, uuid } from '@/utils'
import { config } from './shared' import { config } from './shared'
import { pick } from 'lodash-es' import { pick } from 'lodash-es'
import { useTemplateRef } from 'vue'
import type { DropdownOption, DataTableInst } from 'naive-ui' import type { DropdownOption, DataTableInst, DataTableProps } from 'naive-ui'
import type { ComponentSize } from '@/types' import type { ComponentSize } from '@/types'
import type { import type {
C as CType, C as CType,
@ -38,8 +39,8 @@ export default defineComponent({
setup(props, ctx) { setup(props, ctx) {
const { expose, emit } = ctx const { expose, emit } = ctx
const rTableInst = ref<RTableInst>() const rTableInst = useTemplateRef<RTableInst>('rTableInst')
const wrapperRef = ref<HTMLElement>() const wrapperRef = useTemplateRef<HTMLElement>('wrapperRef')
const uuidWrapper = uuid(16) // wrapper id const uuidWrapper = uuid(16) // wrapper id
const uuidTable = uuid(16) // table id const uuidTable = uuid(16) // table id
@ -278,7 +279,7 @@ export default defineComponent({
id: uuidTable, id: uuidTable,
}} }}
{...$attrs} {...$attrs}
{...$props} {...($props as DataTableProps)}
{...propsPopselectValue} {...propsPopselectValue}
rowProps={combineRowProps.bind(this)} rowProps={combineRowProps.bind(this)}
size={privateReactive.size} size={privateReactive.size}

View File

@ -8,7 +8,7 @@ import type {
DataTableBaseColumn, DataTableBaseColumn,
CardProps, CardProps,
} from 'naive-ui' } from 'naive-ui'
import type { VNode, CSSProperties } from 'vue' import type { VNode, CSSProperties, ShallowRef } from 'vue'
import type { Recordable } from '@/types' import type { Recordable } from '@/types'
import type { PrintDomOptions } from '@/utils/dom' import type { PrintDomOptions } from '@/utils/dom'
@ -34,7 +34,7 @@ export interface PrintTableOptions extends PrintDomOptions {}
export interface TableProvider { export interface TableProvider {
uuidWrapper: string uuidWrapper: string
uuidTable: string uuidTable: string
wrapperRef: Ref<HTMLElement | undefined> wrapperRef: Readonly<ShallowRef<HTMLElement | null>>
} }
export interface C extends DataTableBaseColumn { export interface C extends DataTableBaseColumn {

View File

@ -16,6 +16,8 @@ import { RIcon } from '@/components'
import { tooltipProps } from 'naive-ui' import { tooltipProps } from 'naive-ui'
import type { TooltipProps } from 'naive-ui'
export default defineComponent({ export default defineComponent({
name: 'TooltipIcon', name: 'TooltipIcon',
props: { props: {
@ -58,7 +60,7 @@ export default defineComponent({
const { Icon } = this const { Icon } = this
return this.tooltipText ? ( return this.tooltipText ? (
<NTooltip {...this.$props}> <NTooltip {...(this.$props as TooltipProps)}>
{{ {{
trigger: () => <Icon />, trigger: () => <Icon />,
default: () => this.tooltipText, default: () => this.tooltipText,

View File

@ -79,7 +79,7 @@ export const piniaKeepAliveStore = defineStore(
persist: { persist: {
key: APP_CATCH_KEY.appPiniaKeepAliveStore, key: APP_CATCH_KEY.appPiniaKeepAliveStore,
storage: window.sessionStorage, storage: window.sessionStorage,
paths: ['keepAliveInclude'], pick: ['keepAliveInclude'],
}, },
}, },
) )

View File

@ -446,7 +446,7 @@ export const piniaMenuStore = defineStore(
persist: { persist: {
key: APP_CATCH_KEY.appPiniaMenuStore, key: APP_CATCH_KEY.appPiniaMenuStore,
storage: window.localStorage, storage: window.localStorage,
paths: ['breadcrumbOptions', 'menuKey', 'menuTagOptions', 'collapsed'], pick: ['breadcrumbOptions', 'menuKey', 'menuTagOptions', 'collapsed'],
}, },
}, },
) )

View File

@ -104,7 +104,7 @@ export const piniaSigningStore = defineStore(
{ {
persist: { persist: {
key: APP_CATCH_KEY.appPiniaSigningStore, key: APP_CATCH_KEY.appPiniaSigningStore,
paths: ['signingCallback'], pick: ['signingCallback'],
storage: window.localStorage, storage: window.localStorage,
}, },
}, },

View File

@ -10,7 +10,7 @@ import type { RChartType } from '@/components'
const Echart = defineComponent({ const Echart = defineComponent({
name: 'REchart', name: 'REchart',
setup() { setup() {
const [register, { getChartInstance, dispose, render, isDispose }] = const [register, { getChartInstance, dispose, render, isDisposed }] =
useChart() useChart()
const [ const [
register2, register2,
@ -18,7 +18,7 @@ const Echart = defineComponent({
getChartInstance: getChartInstance2, getChartInstance: getChartInstance2,
dispose: dispose2, dispose: dispose2,
render: render2, render: render2,
isDispose: isDispose2, isDisposed: isDisposed2,
}, },
] = useChart() ] = useChart()
@ -26,6 +26,7 @@ const Echart = defineComponent({
const chartAria = ref(false) const chartAria = ref(false)
const state = reactive({ const state = reactive({
loading: false, loading: false,
loading1: false,
}) })
const baseOptions = { const baseOptions = {
@ -207,10 +208,10 @@ const Echart = defineComponent({
} }
const mountChart = () => { const mountChart = () => {
if (isDispose()) { if (isDisposed()) {
render() render()
} else { } else {
window.$message.warning('不可以重复渲染图表~') window.$message.warning('图表已渲染~')
} }
} }
@ -219,14 +220,20 @@ const Echart = defineComponent({
} }
const updateChartOptions = () => { const updateChartOptions = () => {
state.loading1 = true
const createData = () => Math.floor((Math.random() + 1) * 100) const createData = () => Math.floor((Math.random() + 1) * 100)
setTimeout(() => {
baseLineOptions.value.series[0].data = new Array(7) baseLineOptions.value.series[0].data = new Array(7)
.fill(0) .fill(0)
.map(() => createData()) .map(() => createData())
baseLineOptions.value.series[1].data = new Array(7) baseLineOptions.value.series[1].data = new Array(7)
.fill(0) .fill(0)
.map(() => createData()) .map(() => createData())
state.loading1 = false
}, 1000)
} }
return { return {
@ -245,11 +252,12 @@ const Echart = defineComponent({
register2, register2,
dispose2, dispose2,
render2, render2,
isDispose2, isDisposed2,
} }
}, },
render() { render() {
const { register, register2, dispose2, render2, isDispose2 } = this const { register, register2, dispose2, render2, isDisposed2, loading1 } =
this
return ( return (
<div class="echart"> <div class="echart">
@ -266,6 +274,13 @@ const Echart = defineComponent({
<NButton onClick={this.updateChartOptions.bind(this)}> <NButton onClick={this.updateChartOptions.bind(this)}>
</NButton> </NButton>
<NButton
onClick={() => {
this.loading1 = !this.loading1
}}
>
{`${this.loading1 ? '关闭' : '开启'}`}
</NButton>
</NFlex> </NFlex>
<div class="chart--container"> <div class="chart--container">
<RChart <RChart
@ -275,6 +290,7 @@ const Echart = defineComponent({
options={this.baseLineOptions} options={this.baseLineOptions}
showAria={this.chartAria} showAria={this.chartAria}
preset="card" preset="card"
loading={loading1}
/> />
</div> </div>
</NCard> </NCard>
@ -283,7 +299,7 @@ const Echart = defineComponent({
<NFlex> <NFlex>
<NButton <NButton
onClick={() => { onClick={() => {
if (isDispose2()) { if (isDisposed2()) {
render2() render2()
} else { } else {
window.$message.warning('不可以重复渲染图表~') window.$message.warning('不可以重复渲染图表~')

View File

@ -27,6 +27,8 @@ import { getStorage } from '@/utils'
import { useVueRouter } from '@/hooks' import { useVueRouter } from '@/hooks'
import { APP_CATCH_KEY } from '@/app-config' import { APP_CATCH_KEY } from '@/app-config'
import type { ResultProps } from 'naive-ui'
const PageResult = defineComponent({ const PageResult = defineComponent({
name: 'PageResult', name: 'PageResult',
props: { props: {
@ -56,7 +58,7 @@ const PageResult = defineComponent({
return ( return (
<div class="error-page"> <div class="error-page">
<NResult <NResult
{...this.$props} {...(this.$props as ResultProps)}
status="500" status="500"
title="404 资源不存在" title="404 资源不存在"
description="小调皮你走错地方了" description="小调皮你走错地方了"

View File

@ -91,6 +91,7 @@ export default defineComponent({
type="password" type="password"
showPasswordOn="click" showPasswordOn="click"
placeholder={$t('views.login.index.PasswordPlaceholder')} placeholder={$t('views.login.index.PasswordPlaceholder')}
onKeydown={(e) => e.key === 'Enter' && this.handleLogin()}
/> />
</NFormItem> </NFormItem>
<NButton <NButton

View File

@ -1,10 +1,10 @@
/* eslint-disable */ /* eslint-disable */
/* prettier-ignore */
// @ts-nocheck // @ts-nocheck
// Generated by unplugin-vue-components // Generated by unplugin-vue-components
// Read more: https://github.com/vuejs/core/pull/3399 // Read more: https://github.com/vuejs/core/pull/3399
export {} export {}
/* prettier-ignore */
declare module 'vue' { declare module 'vue' {
export interface GlobalComponents { export interface GlobalComponents {
RouterLink: typeof import('vue-router')['RouterLink'] RouterLink: typeof import('vue-router')['RouterLink']