mirror of
https://github.com/XiaoDaiGua-Ray/ray-template.git
synced 2025-04-05 19:42:07 +08:00
v4.1.8版本发布
This commit is contained in:
parent
6f98e8fb0d
commit
17c5ca7e50
16
CHANGELOG.md
16
CHANGELOG.md
@ -1,5 +1,21 @@
|
||||
# CHANGE LOG
|
||||
|
||||
## 4.1.8
|
||||
|
||||
### Feats
|
||||
|
||||
- 更新 `vite` 版本至 `v4.4.9`
|
||||
- 更新 `vue-hooks-plus` 版本至 `v1.8.1`
|
||||
- 更新了 RayTable 的一些事件的命名
|
||||
- `RayChart` 组件做了一些调整
|
||||
- 支持指定 observer 监听对象,默认为 chart 组件本身
|
||||
- 默认开启 autoChangeTheme 功能
|
||||
- 支持配置 throttleWait 节流等待时间,默认 500ms
|
||||
- 支持通过配置 `desginConfig.echartTheme` 属性指定 `echart theme`。并且只需按照约定方式注册的主题,只需要指定主题名称,即可完成 `light` `dark` 两种主题指定
|
||||
- RayChartInst 新增 dispose render 方法,允许手动渲染与卸载 chart 图
|
||||
- 新增 animation 属性,如果为 true 则会强制触发渲染过渡动画。该配置受 `options.animation` 属性影响,如果该配置为 false 则不会启用过渡动画
|
||||
- 移除反转色功能
|
||||
|
||||
## 4.1.7
|
||||
|
||||
### Feats
|
||||
|
@ -41,7 +41,7 @@
|
||||
"sass": "^1.54.3",
|
||||
"screenfull": "^6.0.2",
|
||||
"vue": "^3.3.4",
|
||||
"vue-hooks-plus": "1.7.6",
|
||||
"vue-hooks-plus": "1.8.1",
|
||||
"vue-i18n": "^9.2.2",
|
||||
"vue-router": "^4.2.4",
|
||||
"vuedraggable": "^4.1.0",
|
||||
@ -85,7 +85,7 @@
|
||||
"typescript": "^5.0.2",
|
||||
"unplugin-auto-import": "^0.15.0",
|
||||
"unplugin-vue-components": "^0.25.1",
|
||||
"vite": "^4.3.9",
|
||||
"vite": "^4.4.9",
|
||||
"vite-plugin-compression": "^0.5.1",
|
||||
"vite-plugin-ejs": "^1.6.4",
|
||||
"vite-plugin-eslint": "1.8.1",
|
||||
|
@ -60,4 +60,10 @@ export const APP_THEME: AppTheme = {
|
||||
* 地址: <https://www.naiveui.com/zh-CN/dark/docs/customize-theme#%E4%BD%BF%E7%94%A8-peers-%E4%B8%BB%E9%A2%98%E5%8F%98%E9%87%8F>
|
||||
*/
|
||||
APP_NAIVE_UI_THEME_OVERRIDES: {},
|
||||
/**
|
||||
*
|
||||
* 配置 echart 主题颜色
|
||||
* 约定配置时以:主题名称为文件名,其文件夹下两个主题风格的 json 文件。并且暗色主题必须为 xxx-dark.json
|
||||
*/
|
||||
echartTheme: 'macarons',
|
||||
}
|
||||
|
@ -5,4 +5,10 @@
|
||||
outline: none;
|
||||
box-sizing: border-box;
|
||||
transition: width 0.35s var(--r-bezier);
|
||||
|
||||
& .ray-chart__container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
|
@ -36,17 +36,19 @@ import {
|
||||
PictorialBarChart,
|
||||
} from 'echarts/charts' // 系列类型(后缀都为 `SeriesOption`)
|
||||
import { LabelLayout, UniversalTransition } from 'echarts/features' // 标签自动布局, 全局过渡动画等特性
|
||||
import { CanvasRenderer } from 'echarts/renderers' // `echarts` 渲染器
|
||||
import {
|
||||
CanvasRenderer,
|
||||
// SVGRenderer,
|
||||
} from 'echarts/renderers' // `echarts` 渲染器
|
||||
|
||||
import { useSetting } from '@/store'
|
||||
import { cloneDeep, throttle } from 'lodash-es'
|
||||
import { on, off, completeSize } from '@/utils/element'
|
||||
import { call } from '@/utils/vue/index'
|
||||
import { setupChartTheme, loadingOptions } from './helper'
|
||||
import { LAYOUT_CONTENT_REF } from '@/appConfig/routerConfig'
|
||||
import { APP_THEME } from '@/appConfig/designConfig'
|
||||
|
||||
import type { PropType } from 'vue'
|
||||
import type { EChartsInstance } from '@/types/modules/component'
|
||||
import type { AnyFC, MaybeArray } from '@/types/modules/utils'
|
||||
import type { DebouncedFunc } from 'lodash-es'
|
||||
import type {
|
||||
@ -54,9 +56,15 @@ import type {
|
||||
AutoResize,
|
||||
ChartTheme,
|
||||
} from '@/components/RayChart/type'
|
||||
import type { UseResizeObserverReturn } from '@vueuse/core'
|
||||
import type {
|
||||
UseResizeObserverReturn,
|
||||
MaybeComputedElementRef,
|
||||
MaybeElement,
|
||||
} from '@vueuse/core'
|
||||
import type { ECharts, EChartsCoreOption } from 'echarts/core'
|
||||
|
||||
export type EChartsExtensionInstallRegisters = typeof CanvasRenderer
|
||||
export type { RayChartInst } from './type'
|
||||
|
||||
const RayChart = defineComponent({
|
||||
name: 'RayChart',
|
||||
@ -116,21 +124,19 @@ const RayChart = defineComponent({
|
||||
type: Object as PropType<echarts.EChartsCoreOption>,
|
||||
default: () => ({}),
|
||||
},
|
||||
success: {
|
||||
onSuccess: {
|
||||
/**
|
||||
*
|
||||
* 返回 chart 实例
|
||||
*
|
||||
* 渲染成功回调函数
|
||||
*
|
||||
* () => EChartsInstance
|
||||
* () => ECharts
|
||||
*/
|
||||
type: [Function, Array] as PropType<
|
||||
MaybeArray<(e: EChartsInstance) => void>
|
||||
>,
|
||||
type: [Function, Array] as PropType<MaybeArray<(e: ECharts) => void>>,
|
||||
default: null,
|
||||
},
|
||||
error: {
|
||||
onError: {
|
||||
/**
|
||||
*
|
||||
* 渲染失败回调函数
|
||||
@ -148,13 +154,12 @@ const RayChart = defineComponent({
|
||||
/**
|
||||
*
|
||||
* 是否自动跟随模板主题切换
|
||||
*
|
||||
* 如果开启此属性, 则会覆盖 `theme` 属性
|
||||
*
|
||||
* 注意: 这个属性重度依赖此模板, 所以默认不开启. 并且动态切换主题有一定的性能问题
|
||||
* 注意: 这个属性重度依赖此模板
|
||||
*/
|
||||
type: Boolean,
|
||||
default: false,
|
||||
default: true,
|
||||
},
|
||||
use: {
|
||||
/**
|
||||
@ -180,15 +185,37 @@ const RayChart = defineComponent({
|
||||
type: Object as PropType<LoadingOptions>,
|
||||
default: () => loadingOptions(),
|
||||
},
|
||||
observer: {
|
||||
/**
|
||||
*
|
||||
* 需要被监听尺寸的元素
|
||||
* 需要开启 autoResize 才能生效
|
||||
* 默认以父元素作为监听对象
|
||||
*/
|
||||
type: Object as PropType<MaybeComputedElementRef<MaybeElement>>,
|
||||
default: null,
|
||||
},
|
||||
throttleWait: {
|
||||
/** 节流等待时间 */
|
||||
type: Number,
|
||||
default: 500,
|
||||
},
|
||||
animation: {
|
||||
/** 是否强制启用渲染动画 */
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
setup(props, { expose }) {
|
||||
const settingStore = useSetting()
|
||||
const { themeValue } = storeToRefs(settingStore)
|
||||
const rayChartRef = ref<HTMLElement>() // `echart` 容器实例
|
||||
const echartInstanceRef = ref<EChartsInstance>() // `echart` 拷贝实例, 解决直接使用响应式实例带来的问题
|
||||
let echartInstance: EChartsInstance // `echart` 实例
|
||||
let resizeThrottle: DebouncedFunc<AnyFC> // resize 防抖方法实例
|
||||
let resizeOvserverReturn: UseResizeObserverReturn | undefined
|
||||
const rayChartWrapperRef = ref<HTMLElement>()
|
||||
const echartInstanceRef = ref<ECharts>() // `echart` 实例
|
||||
let echartInstance: ECharts | null // `echart` 拷贝实例, 解决直接使用响应式实例带来的问题
|
||||
let resizeThrottleReturn: DebouncedFunc<AnyFC> | null // resize 防抖方法实例
|
||||
let resizeOvserverReturn: UseResizeObserverReturn | null
|
||||
const { echartTheme } = APP_THEME
|
||||
|
||||
const cssVarsRef = computed(() => {
|
||||
const cssVars = {
|
||||
@ -198,9 +225,6 @@ const RayChart = defineComponent({
|
||||
|
||||
return cssVars
|
||||
})
|
||||
const modelLoadingOptions = computed(() =>
|
||||
loadingOptions(props.loadingOptions),
|
||||
)
|
||||
|
||||
/**
|
||||
*
|
||||
@ -237,7 +261,7 @@ const RayChart = defineComponent({
|
||||
echarts.use([CanvasRenderer]) // 注册渲染器
|
||||
|
||||
try {
|
||||
echarts.use(props.use)
|
||||
echarts.use(props.use?.filter(Boolean))
|
||||
} catch (e) {
|
||||
console.error(
|
||||
'Error: wrong property and method passed in extend attribute',
|
||||
@ -253,10 +277,17 @@ const RayChart = defineComponent({
|
||||
*
|
||||
* 如果有需要特殊全局配置的可以在此继续写...
|
||||
*/
|
||||
const combineChartOptions = () => {
|
||||
let options = cloneDeep(props.options)
|
||||
const combineChartOptions = (ops: EChartsCoreOption) => {
|
||||
let options = cloneDeep(ops)
|
||||
|
||||
const assign = (opts: object) => Object.assign({}, options, opts)
|
||||
const assign = (opts: object) =>
|
||||
Object.assign(
|
||||
{
|
||||
animation: true,
|
||||
},
|
||||
options,
|
||||
opts,
|
||||
)
|
||||
|
||||
if (props.showAria) {
|
||||
options = assign({
|
||||
@ -277,17 +308,16 @@ const RayChart = defineComponent({
|
||||
* 渲染 `echart`
|
||||
*
|
||||
* 缓存两个实例
|
||||
*
|
||||
* 直接使用响应式代理实例会出现诡异的问题, 例如 `legend` 点击时报错
|
||||
*/
|
||||
const renderChart = (theme: ChartTheme = 'macarons') => {
|
||||
const renderChart = (theme: ChartTheme = echartTheme) => {
|
||||
/** 获取 dom 容器 */
|
||||
const element = rayChartRef.value as HTMLElement
|
||||
/** 获取配置项 */
|
||||
const options = combineChartOptions()
|
||||
const options = combineChartOptions(props.options)
|
||||
/** 获取 dom 容器实际宽高 */
|
||||
const { height, width } = element.getBoundingClientRect()
|
||||
const { success, error } = props
|
||||
const { onSuccess, onError } = props
|
||||
|
||||
try {
|
||||
/** 注册主题 */
|
||||
@ -305,16 +335,22 @@ const RayChart = defineComponent({
|
||||
echartInstanceRef.value = echartInstance
|
||||
|
||||
/** 设置 options 配置项 */
|
||||
options && echartInstance.setOption(options)
|
||||
options && echartInstance.setOption({})
|
||||
|
||||
if (props.animation) {
|
||||
setTimeout(() => {
|
||||
options && echartInstance?.setOption(options)
|
||||
})
|
||||
}
|
||||
|
||||
/** 渲染成功回调 */
|
||||
if (success) {
|
||||
call(success, echartInstance)
|
||||
if (onSuccess) {
|
||||
call(onSuccess, echartInstance)
|
||||
}
|
||||
} catch (e) {
|
||||
/** 渲染失败回调 */
|
||||
if (error) {
|
||||
call(error)
|
||||
if (onError) {
|
||||
call(onError)
|
||||
}
|
||||
|
||||
console.error('RayChart render error: ', e)
|
||||
@ -329,9 +365,9 @@ const RayChart = defineComponent({
|
||||
*/
|
||||
const renderThemeChart = (bool?: boolean) => {
|
||||
if (props.autoChangeTheme) {
|
||||
bool ? renderChart('macarons-dark') : renderChart()
|
||||
bool ? renderChart(`${echartTheme}-dark`) : renderChart()
|
||||
|
||||
return void 0
|
||||
return
|
||||
}
|
||||
|
||||
if (!props.theme) {
|
||||
@ -357,10 +393,51 @@ const RayChart = defineComponent({
|
||||
}
|
||||
}
|
||||
|
||||
const mount = () => {
|
||||
// 避免重复渲染
|
||||
if (echartInstance?.getDom()) {
|
||||
console.warn(
|
||||
'RayChart mount: There is a chart instance already initialized on the dom. Execution was interrupted',
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if (props.autoChangeTheme) {
|
||||
/** 注册 echarts */
|
||||
renderThemeChart(themeValue.value)
|
||||
} else {
|
||||
props.theme ? renderChart(`${echartTheme}-dark`) : renderChart()
|
||||
}
|
||||
|
||||
/** 注册事件 */
|
||||
if (props.autoResize) {
|
||||
resizeThrottleReturn = throttle(resizeChart, props.throttleWait)
|
||||
/** 监听内容区域尺寸变化更新 chart */
|
||||
resizeOvserverReturn = useResizeObserver(
|
||||
props.observer || rayChartWrapperRef,
|
||||
resizeThrottleReturn,
|
||||
)
|
||||
|
||||
on(window, 'resize', resizeThrottleReturn)
|
||||
}
|
||||
}
|
||||
|
||||
const unmount = () => {
|
||||
/** 卸载 echarts */
|
||||
destroyChart()
|
||||
/** 卸载事件柄 */
|
||||
resizeThrottleReturn && off(window, 'resize', resizeThrottleReturn)
|
||||
/** 注销防抖 */
|
||||
resizeThrottleReturn?.cancel()
|
||||
/** 注销 observer 监听 */
|
||||
resizeOvserverReturn?.stop?.()
|
||||
}
|
||||
|
||||
/** 监听全局主题变化, 然后重新渲染对应主题 echarts */
|
||||
watch(
|
||||
() => [themeValue.value],
|
||||
([theme]) => {
|
||||
() => themeValue.value,
|
||||
(theme) => {
|
||||
/**
|
||||
*
|
||||
* Q: 为什么需要重新卸载再渲染
|
||||
@ -375,19 +452,19 @@ const RayChart = defineComponent({
|
||||
},
|
||||
)
|
||||
|
||||
/**
|
||||
*
|
||||
* 贴花跟随主题渲染
|
||||
*
|
||||
* 自动跟随模板主题或者指定主题皆可
|
||||
*/
|
||||
watch(
|
||||
() => props.showAria,
|
||||
() => {
|
||||
destroyChart()
|
||||
|
||||
/**
|
||||
*
|
||||
* 贴花跟随主题渲染
|
||||
*
|
||||
* 自动跟随模板主题或者指定主题皆可
|
||||
*/
|
||||
if (props.autoChangeTheme || props.theme) {
|
||||
themeValue.value ? renderChart('macarons-dark') : renderChart()
|
||||
themeValue.value ? renderChart(`${echartTheme}-dark`) : renderChart()
|
||||
} else {
|
||||
renderChart()
|
||||
}
|
||||
@ -397,27 +474,36 @@ const RayChart = defineComponent({
|
||||
/** 显示/隐藏加载动画 */
|
||||
watch(
|
||||
() => props.loading,
|
||||
(newData) => {
|
||||
newData
|
||||
? echartInstance?.showLoading(modelLoadingOptions.value)
|
||||
(ndata) => {
|
||||
ndata
|
||||
? echartInstance?.showLoading(props.loadingOptions)
|
||||
: echartInstance?.hideLoading()
|
||||
},
|
||||
)
|
||||
|
||||
/** 监听 options 变化 */
|
||||
if (props.watchOptions) {
|
||||
/** 监听 options 变化 */
|
||||
watch(
|
||||
() => props.watchOptions,
|
||||
() => {
|
||||
() => props.options,
|
||||
(noptions) => {
|
||||
/** 重新组合 options */
|
||||
const options = combineChartOptions()
|
||||
const options = combineChartOptions(noptions)
|
||||
|
||||
/** 如果 options 发生变动更新 echarts */
|
||||
echartInstance?.setOption(options)
|
||||
},
|
||||
{
|
||||
deep: true,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
expose({
|
||||
echart: echartInstanceRef,
|
||||
dispose: unmount,
|
||||
render: mount,
|
||||
})
|
||||
|
||||
onBeforeMount(async () => {
|
||||
/** 注册 echarts 组件与渲染器 */
|
||||
await registerChartCore()
|
||||
@ -425,51 +511,25 @@ const RayChart = defineComponent({
|
||||
|
||||
onMounted(() => {
|
||||
nextTick(() => {
|
||||
/** 注册 echarts */
|
||||
if (props.autoChangeTheme) {
|
||||
renderThemeChart(themeValue.value)
|
||||
} else {
|
||||
props.theme ? renderChart('macarons-dark') : renderChart()
|
||||
}
|
||||
|
||||
/** 注册事件 */
|
||||
if (props.autoResize) {
|
||||
resizeThrottle = throttle(resizeChart, 500)
|
||||
|
||||
on(window, 'resize', resizeThrottle)
|
||||
}
|
||||
|
||||
/** 监听内容区域尺寸变化更新 chart */
|
||||
resizeOvserverReturn = useResizeObserver(
|
||||
LAYOUT_CONTENT_REF.value as unknown as Ref<HTMLElement>,
|
||||
resizeThrottle,
|
||||
)
|
||||
mount()
|
||||
})
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
/** 卸载 echarts */
|
||||
destroyChart()
|
||||
/** 卸载事件柄 */
|
||||
off(window, 'resize', resizeThrottle)
|
||||
/** 注销防抖 */
|
||||
resizeThrottle.cancel()
|
||||
resizeOvserverReturn?.stop?.()
|
||||
})
|
||||
|
||||
expose({
|
||||
echart: echartInstanceRef,
|
||||
unmount()
|
||||
})
|
||||
|
||||
return {
|
||||
rayChartRef,
|
||||
cssVarsRef,
|
||||
echartInstance: echartInstanceRef,
|
||||
rayChartWrapperRef,
|
||||
}
|
||||
},
|
||||
render() {
|
||||
return (
|
||||
<div class="ray-chart" style={[this.cssVarsRef]} ref="rayChartRef"></div>
|
||||
<div class="ray-chart" style={[this.cssVarsRef]} ref="rayChartWrapperRef">
|
||||
<div class="ray-chart__container" ref="rayChartRef"></div>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
})
|
||||
|
@ -9,6 +9,8 @@
|
||||
* @remark 今天也是元气满满撸代码的一天
|
||||
*/
|
||||
|
||||
import type { ECharts, EChartsCoreOption } from 'echarts/core'
|
||||
|
||||
export interface ChartThemeRawModules {
|
||||
default: Record<string, UnknownObjectKey>
|
||||
}
|
||||
@ -41,3 +43,26 @@ export type AutoResize =
|
||||
}
|
||||
|
||||
export type ChartTheme = 'macarons-dark' | string | object | 'macarons'
|
||||
|
||||
export interface RayChartInst {
|
||||
/**
|
||||
*
|
||||
* echart 实例
|
||||
* 访问当前 chart 图所有方法与属性
|
||||
*
|
||||
* @default undefined
|
||||
*/
|
||||
echart: Ref<ECharts | undefined>
|
||||
/**
|
||||
*
|
||||
* 手动卸载当前 chart 图
|
||||
* 注意:不会卸载当前组件,仅仅是卸载 chart
|
||||
*/
|
||||
dispose: () => void
|
||||
/**
|
||||
*
|
||||
* 手动渲染 chart 图
|
||||
* 注意:会根据当前的 options 配置项与 props 配置项重新渲染 chart
|
||||
*/
|
||||
render: () => void
|
||||
}
|
||||
|
@ -1,3 +1,6 @@
|
||||
import RayIframe from './src/index'
|
||||
|
||||
import type { RayIframeInst } from './src/index'
|
||||
|
||||
export default RayIframe
|
||||
export type { RayIframeInst }
|
||||
|
@ -20,6 +20,10 @@ import type { PropType } from 'vue'
|
||||
import type { MaybeArray } from '@/types/modules/utils'
|
||||
import type { SpinProps } from 'naive-ui'
|
||||
|
||||
export interface RayIframeInst {
|
||||
iframe: Ref<HTMLIFrameElement>
|
||||
}
|
||||
|
||||
const RayIframe = defineComponent({
|
||||
name: 'RayIframe',
|
||||
props: {
|
||||
@ -73,7 +77,7 @@ const RayIframe = defineComponent({
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
success: {
|
||||
onSuccess: {
|
||||
/**
|
||||
*
|
||||
* iframe 加载成功回调
|
||||
@ -84,7 +88,7 @@ const RayIframe = defineComponent({
|
||||
>,
|
||||
default: null,
|
||||
},
|
||||
error: {
|
||||
onError: {
|
||||
/**
|
||||
*
|
||||
* iframe 加载失败回调
|
||||
@ -119,20 +123,20 @@ const RayIframe = defineComponent({
|
||||
const iframeLoadSuccess = (e: Event) => {
|
||||
spinShow.value = false
|
||||
|
||||
const { success } = props
|
||||
const { onSuccess } = props
|
||||
|
||||
if (success) {
|
||||
call(success, iframeRef.value as HTMLIFrameElement, e)
|
||||
if (onSuccess) {
|
||||
call(onSuccess, iframeRef.value as HTMLIFrameElement, e)
|
||||
}
|
||||
}
|
||||
|
||||
const iframeLoadError = (e: Event) => {
|
||||
spinShow.value = false
|
||||
|
||||
const { error } = props
|
||||
const { onError } = props
|
||||
|
||||
if (error) {
|
||||
call(error, e)
|
||||
if (onError) {
|
||||
call(onError, e)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,21 +1,10 @@
|
||||
@keyframes scaleScreenfull {
|
||||
0% {
|
||||
transform: scale(1);
|
||||
}
|
||||
50% {
|
||||
transform: scale(1.3);
|
||||
}
|
||||
100% {
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
.ray-table {
|
||||
& .ray-table-icon {
|
||||
transition: transform 0.3s var(--r-bezier);
|
||||
|
||||
&:hover {
|
||||
animation: scaleScreenfull 0.3s linear;
|
||||
@include scaleAnimate();
|
||||
animation: elementScale 0.3s linear;
|
||||
animation-direction: alternate;
|
||||
}
|
||||
}
|
||||
|
@ -58,8 +58,7 @@ import type { ComponentSize } from '@/types/modules/component'
|
||||
const RayTable = defineComponent({
|
||||
name: 'RayTable',
|
||||
props: props,
|
||||
emits: ['update:columns', 'exportSuccess', 'exportError'],
|
||||
setup(props, { emit, expose }) {
|
||||
setup(props, { expose }) {
|
||||
const rayTableInstance = ref<DataTableInst>()
|
||||
|
||||
const tableUUID = uuid(16) // 表格 id, 用于打印表格
|
||||
@ -68,7 +67,15 @@ const RayTable = defineComponent({
|
||||
const modelColumns = computed({
|
||||
get: () => props.columns,
|
||||
set: (arr) => {
|
||||
emit('update:columns', arr)
|
||||
const { onUpdateColumns, 'onUpdate:columns': _onUpdateColumns } = props
|
||||
|
||||
if (onUpdateColumns) {
|
||||
call(onUpdateColumns, arr)
|
||||
}
|
||||
|
||||
if (_onUpdateColumns) {
|
||||
call(_onUpdateColumns, arr)
|
||||
}
|
||||
},
|
||||
}) as unknown as WritableComputedRef<ActionOptions[]>
|
||||
const menuConfig = reactive({
|
||||
@ -76,7 +83,6 @@ const RayTable = defineComponent({
|
||||
y: 0,
|
||||
showMenu: false,
|
||||
})
|
||||
let prevRightClickIndex = -1 // 缓存上次点击索引位置
|
||||
const cssVars = computed(() => {
|
||||
const cssVar = {
|
||||
'--ray-table-header-space': props.tableHeaderSpace,
|
||||
@ -86,6 +92,7 @@ const RayTable = defineComponent({
|
||||
})
|
||||
const tableSize = ref(props.size)
|
||||
const tableMethods = ref<Omit<DataTableInst, 'clearFilter'>>()
|
||||
let prevRightClickIndex = -1 // 缓存上次点击索引位置
|
||||
|
||||
/** 注入相关属性 */
|
||||
provide('tableSettingProvider', {
|
||||
@ -111,17 +118,12 @@ const RayTable = defineComponent({
|
||||
key: string | number,
|
||||
option: DropdownOption,
|
||||
) => {
|
||||
const { onRightMenuClick, 'onUpdate:rightMenuClick': _onRightMenuClick } =
|
||||
props
|
||||
const { onRightMenuClick } = props
|
||||
|
||||
if (onRightMenuClick) {
|
||||
call(onRightMenuClick, key, prevRightClickIndex, option)
|
||||
}
|
||||
|
||||
if (_onRightMenuClick) {
|
||||
call(_onRightMenuClick, key, prevRightClickIndex, option)
|
||||
}
|
||||
|
||||
menuConfig.showMenu = false
|
||||
}
|
||||
|
||||
@ -136,22 +138,24 @@ const RayTable = defineComponent({
|
||||
const handleRowProps = (arr: ActionOptions, idx: number) => {
|
||||
const interceptRowProps = props.rowProps?.(arr, idx)
|
||||
|
||||
const contextmenu = modelRightClickMenu.value.length
|
||||
? (e: MouseEvent) => {
|
||||
e.preventDefault()
|
||||
|
||||
prevRightClickIndex = idx
|
||||
menuConfig.showMenu = false
|
||||
|
||||
nextTick().then(() => {
|
||||
menuConfig.showMenu = true
|
||||
menuConfig.x = e.clientX
|
||||
menuConfig.y = e.clientY
|
||||
})
|
||||
}
|
||||
: void 0
|
||||
|
||||
return {
|
||||
...interceptRowProps,
|
||||
onContextmenu: (e: MouseEvent) => {
|
||||
e.preventDefault()
|
||||
|
||||
prevRightClickIndex = idx
|
||||
|
||||
menuConfig.showMenu = false
|
||||
|
||||
nextTick().then(() => {
|
||||
menuConfig.showMenu = true
|
||||
|
||||
menuConfig.x = e.clientX
|
||||
menuConfig.y = e.clientY
|
||||
})
|
||||
},
|
||||
onContextmenu: contextmenu,
|
||||
}
|
||||
}
|
||||
|
||||
@ -164,6 +168,8 @@ const RayTable = defineComponent({
|
||||
* 按需导入 `xlsx` 减少体积, 不依赖传统 `file save` 插件导出方式
|
||||
*/
|
||||
const handleExportPositive = async () => {
|
||||
const { onExportSuccess, onExportError } = props
|
||||
|
||||
if (props.data.length && props.columns.length) {
|
||||
try {
|
||||
await exportFileToXLSX(
|
||||
@ -174,9 +180,9 @@ const RayTable = defineComponent({
|
||||
},
|
||||
)
|
||||
|
||||
emit('exportSuccess')
|
||||
onExportSuccess && call(onExportSuccess)
|
||||
} catch (e) {
|
||||
emit('exportError')
|
||||
onExportError && call(onExportError)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -276,21 +282,16 @@ const RayTable = defineComponent({
|
||||
...this.$slots,
|
||||
}}
|
||||
</NDataTable>
|
||||
{this.showMenu ? (
|
||||
// 右键菜单
|
||||
<NDropdown
|
||||
show={this.showMenu}
|
||||
placement="bottom-start"
|
||||
trigger="manual"
|
||||
x={this.x}
|
||||
y={this.y}
|
||||
options={this.modelRightClickMenu}
|
||||
onClickoutside={() => (this.showMenu = false)}
|
||||
onSelect={this.handleRightMenuSelect.bind(this)}
|
||||
/>
|
||||
) : (
|
||||
''
|
||||
)}
|
||||
<NDropdown
|
||||
show={this.showMenu}
|
||||
placement="bottom-start"
|
||||
trigger="manual"
|
||||
x={this.x}
|
||||
y={this.y}
|
||||
options={this.modelRightClickMenu}
|
||||
onClickoutside={() => (this.showMenu = false)}
|
||||
onSelect={this.handleRightMenuSelect.bind(this)}
|
||||
/>
|
||||
</>
|
||||
),
|
||||
header: () => this.title || <div style="display: none;"></div>,
|
||||
|
@ -15,7 +15,7 @@ import type { PropType, VNode, VNodeChild } from 'vue'
|
||||
import type { DropdownMixedOption } from './type'
|
||||
import type PrintConfiguration from 'print-js'
|
||||
import type { MaybeArray } from '@/types/modules/utils'
|
||||
import type { DropdownOption } from 'naive-ui'
|
||||
import type { DropdownOption, DataTableColumn } from 'naive-ui'
|
||||
|
||||
const rayTableProps = {
|
||||
...dataTableProps, // 继承 `data table props`
|
||||
@ -39,14 +39,6 @@ const rayTableProps = {
|
||||
>,
|
||||
default: null,
|
||||
},
|
||||
'onUpdate:rightMenuClick': {
|
||||
type: [Function, Array] as PropType<
|
||||
MaybeArray<
|
||||
(key: string | number, index: number, option: DropdownOption) => void
|
||||
>
|
||||
>,
|
||||
default: null,
|
||||
},
|
||||
title: {
|
||||
/**
|
||||
*
|
||||
@ -77,16 +69,6 @@ const rayTableProps = {
|
||||
type: Object as PropType<VNode>,
|
||||
default: () => ({}),
|
||||
},
|
||||
showMenu: {
|
||||
/**
|
||||
*
|
||||
* 是否展示右键菜单
|
||||
*
|
||||
* 默认启用
|
||||
*/
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
exportTooltip: {
|
||||
/**
|
||||
*
|
||||
@ -225,7 +207,30 @@ const rayTableProps = {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
/** 导出成功 */
|
||||
onExportSuccess: {
|
||||
type: [Function, Array] as PropType<MaybeArray<() => void>>,
|
||||
default: null,
|
||||
},
|
||||
/** 导出失败 */
|
||||
onExportError: {
|
||||
type: [Function, Array] as PropType<MaybeArray<() => void>>,
|
||||
default: null,
|
||||
},
|
||||
onUpdateColumns: {
|
||||
type: [Function, Array] as PropType<
|
||||
MaybeArray<(arr: DataTableColumn[]) => void>
|
||||
>,
|
||||
default: null,
|
||||
},
|
||||
'onUpdate:columns': {
|
||||
type: [Function, Array] as PropType<
|
||||
MaybeArray<(arr: DataTableColumn[]) => void>
|
||||
>,
|
||||
default: null,
|
||||
},
|
||||
} as const
|
||||
|
||||
export default rayTableProps
|
||||
|
||||
/**
|
||||
|
@ -48,7 +48,6 @@ const SettingDrawer = defineComponent({
|
||||
primaryColorOverride,
|
||||
menuTagSwitch,
|
||||
breadcrumbSwitch,
|
||||
invertSwitch,
|
||||
footerSwitch,
|
||||
contentTransition,
|
||||
} = storeToRefs(settingStore)
|
||||
@ -87,7 +86,6 @@ const SettingDrawer = defineComponent({
|
||||
menuTagSwitch,
|
||||
changeSwitcher,
|
||||
breadcrumbSwitch,
|
||||
invertSwitch,
|
||||
footerSwitch,
|
||||
contentTransitionOptions,
|
||||
contentTransition,
|
||||
@ -155,14 +153,6 @@ const SettingDrawer = defineComponent({
|
||||
}
|
||||
/>
|
||||
</NDescriptionsItem>
|
||||
<NDescriptionsItem label="反转色">
|
||||
<NSwitch
|
||||
v-model:value={this.invertSwitch}
|
||||
onUpdateValue={(bool: boolean) =>
|
||||
this.changeSwitcher(bool, 'invertSwitch')
|
||||
}
|
||||
/>
|
||||
</NDescriptionsItem>
|
||||
</NDescriptions>
|
||||
</NSpace>
|
||||
</NDrawerContent>
|
||||
|
@ -3,8 +3,6 @@ import { getAppRawRoutes } from './routeModules'
|
||||
import { ROOT_ROUTE } from '@/appConfig/appConfig'
|
||||
import { expandRoutes } from '@/router/helper/expandRoutes'
|
||||
|
||||
const { path } = ROOT_ROUTE
|
||||
|
||||
export default async () => [
|
||||
{
|
||||
path: '/',
|
||||
@ -14,7 +12,7 @@ export default async () => [
|
||||
{
|
||||
path: '/',
|
||||
name: 'layout',
|
||||
redirect: path,
|
||||
redirect: ROOT_ROUTE.path,
|
||||
component: Layout,
|
||||
children: expandRoutes(getAppRawRoutes()),
|
||||
},
|
||||
|
@ -32,7 +32,6 @@ export const useSetting = defineStore(
|
||||
reloadRouteSwitch: true, // 刷新路由开关
|
||||
menuTagSwitch: true, // 多标签页开关
|
||||
spinSwitch: false, // 全屏加载
|
||||
invertSwitch: false, // 反转色模式
|
||||
breadcrumbSwitch: true, // 面包屑开关
|
||||
localeLanguage: getAppDefaultLanguage(),
|
||||
lockScreenSwitch: false, // 锁屏开关
|
||||
@ -93,17 +92,6 @@ export const useSetting = defineStore(
|
||||
}
|
||||
}
|
||||
|
||||
/** 动态添加反转色 class name */
|
||||
watch(
|
||||
() => settingState.invertSwitch,
|
||||
(newData) => {
|
||||
const body = document.body
|
||||
const className = 'ray-template--invert'
|
||||
|
||||
newData ? addClass(body, className) : removeClass(body, className)
|
||||
},
|
||||
)
|
||||
|
||||
return {
|
||||
...toRefs(settingState),
|
||||
updateLocale,
|
||||
|
@ -10,7 +10,6 @@ export interface SettingState {
|
||||
spinSwitch: boolean
|
||||
breadcrumbSwitch: boolean
|
||||
localeLanguage: string
|
||||
invertSwitch: boolean
|
||||
lockScreenSwitch: boolean
|
||||
lockScreenInputSwitch: boolean
|
||||
footerSwitch: boolean
|
||||
|
@ -44,17 +44,24 @@ img {
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans",
|
||||
"Droid Sans", "Helvetica Neue", sans-serif;
|
||||
font-family:
|
||||
Inter,
|
||||
-apple-system,
|
||||
BlinkMacSystemFont,
|
||||
"Segoe UI",
|
||||
Roboto,
|
||||
Oxygen,
|
||||
Ubuntu,
|
||||
Cantarell,
|
||||
"Fira Sans",
|
||||
"Droid Sans",
|
||||
"Helvetica Neue",
|
||||
sans-serif;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
body.ray-template--invert {
|
||||
filter: invert(1);
|
||||
}
|
||||
|
||||
body .ray-template__directive--disabled {
|
||||
opacity: 0.3 !important;
|
||||
pointer-events: none !important;
|
||||
|
@ -47,3 +47,17 @@
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin scaleAnimate($scale-from: 1, $scale-to: 1.3) {
|
||||
@keyframes elementScale {
|
||||
0% {
|
||||
transform: scale($scale-from);
|
||||
}
|
||||
50% {
|
||||
transform: scale($scale-to);
|
||||
}
|
||||
100% {
|
||||
transform: scale($scale-from);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -79,4 +79,5 @@ export interface AppTheme {
|
||||
APP_THEME_COLOR: string[]
|
||||
APP_PRIMARY_COLOR: AppPrimaryColor
|
||||
APP_NAIVE_UI_THEME_OVERRIDES: GlobalThemeOverrides
|
||||
echartTheme: string
|
||||
}
|
||||
|
@ -1,10 +1,7 @@
|
||||
import type { ECharts } from 'echarts/core'
|
||||
import type { MenuOption, MenuDividerOption, MenuGroupOption } from 'naive-ui'
|
||||
|
||||
export type ComponentSize = 'small' | 'medium' | 'large'
|
||||
|
||||
export type EChartsInstance = ECharts
|
||||
|
||||
export type Placement = 'top' | 'right' | 'bottom' | 'left'
|
||||
|
||||
export type NaiveMenuOptions = MenuOption | MenuDividerOption | MenuGroupOption
|
||||
|
@ -1,14 +1,15 @@
|
||||
import './index.scss'
|
||||
|
||||
import { NCard, NSwitch, NSpace, NP, NH2 } from 'naive-ui'
|
||||
import { NCard, NSwitch, NSpace, NP, NH2, NButton } from 'naive-ui'
|
||||
import RayChart from '@/components/RayChart/index'
|
||||
|
||||
import type { EChartsInstance } from '@/types/modules/component'
|
||||
import type { ECharts } from 'echarts/core'
|
||||
import type { RayChartInst } from '@/components/RayChart/index'
|
||||
|
||||
const Echart = defineComponent({
|
||||
name: 'REchart',
|
||||
setup() {
|
||||
const baseChartRef = ref()
|
||||
const baseChartRef = ref<RayChartInst>()
|
||||
const chartLoading = ref(false)
|
||||
const chartAria = ref(false)
|
||||
const state = reactive({
|
||||
@ -186,7 +187,7 @@ const Echart = defineComponent({
|
||||
chartAria.value = bool
|
||||
}
|
||||
|
||||
const handleChartRenderSuccess = (chart: EChartsInstance) => {
|
||||
const handleChartRenderSuccess = (chart: ECharts) => {
|
||||
window.$notification.info({
|
||||
title: '可视化图渲染成功回调函数',
|
||||
content: '可视化图渲染成功, 并且返回了当前可视化图实例',
|
||||
@ -196,6 +197,14 @@ const Echart = defineComponent({
|
||||
console.log(baseChartRef.value, chart)
|
||||
}
|
||||
|
||||
const mountChart = () => {
|
||||
baseChartRef.value?.render()
|
||||
}
|
||||
|
||||
const unmountChart = () => {
|
||||
baseChartRef.value?.dispose()
|
||||
}
|
||||
|
||||
return {
|
||||
baseOptions,
|
||||
baseChartRef,
|
||||
@ -207,39 +216,52 @@ const Echart = defineComponent({
|
||||
basePieOptions,
|
||||
baseLineOptions,
|
||||
...toRefs(state),
|
||||
mountChart,
|
||||
unmountChart,
|
||||
}
|
||||
},
|
||||
render() {
|
||||
return (
|
||||
<div class="echart">
|
||||
<NH2>RayChart 组件使用</NH2>
|
||||
<NP>
|
||||
该组件会默认以 200*200
|
||||
宽高进行填充。预设了常用的图、方法组件,如果不满足需求,需要用 use
|
||||
方法进行手动拓展。该组件实现了自动跟随模板主题切换功能,但是动态切换损耗较大,所以默认不启用。
|
||||
该组件可以让你只需要关注 options 的配置,无需关心 chart
|
||||
图的资源管理。并且该组件可以自动监听 options
|
||||
的变化,所以天生支持响应式,可以让你放心的加载异步数据。
|
||||
</NP>
|
||||
<NH2>能跟随主题切换的可视化图</NH2>
|
||||
<NCard title="chart 组件">
|
||||
<ul>
|
||||
<li>
|
||||
<h3>当未获取到宽高时,组件会默认以 200*200 尺寸填充。</h3>
|
||||
</li>
|
||||
<li>
|
||||
<h3>
|
||||
默认启用 autoChangeTheme,自动监听模板主题变化(RayTemplate
|
||||
独有)
|
||||
</h3>
|
||||
</li>
|
||||
<li>
|
||||
<h3>默认启用 watchOptions,自动监听配置项变化</h3>
|
||||
</li>
|
||||
<li>
|
||||
<h3>默认启用 animation,强制启用渲染过渡动画</h3>
|
||||
</li>
|
||||
</ul>
|
||||
</NCard>
|
||||
<NH2>强制渲染过渡动画(animation)</NH2>
|
||||
<NSpace style={['padding: 18px 0']}>
|
||||
<NButton onClick={this.mountChart.bind(this)}>渲染</NButton>
|
||||
<NButton onClick={this.unmountChart.bind(this)}>卸载</NButton>
|
||||
</NSpace>
|
||||
<div class="chart--container">
|
||||
<RayChart
|
||||
ref="baseChartRef"
|
||||
autoChangeTheme
|
||||
options={this.baseLineOptions}
|
||||
showAria={this.chartAria}
|
||||
/>
|
||||
</div>
|
||||
<NH2>渲染成功后运行回调函数</NH2>
|
||||
<div class="chart--container">
|
||||
<RayChart
|
||||
ref="baseChartRef"
|
||||
options={this.basePieOptions}
|
||||
success={this.handleChartRenderSuccess.bind(this)}
|
||||
/>
|
||||
</div>
|
||||
<NH2>不跟随主题切换的暗色主题可视化图</NH2>
|
||||
<div class="chart--container">
|
||||
<RayChart theme="dark" options={this.baseOptions} />
|
||||
<RayChart
|
||||
autoChangeTheme={false}
|
||||
theme="dark"
|
||||
options={this.baseOptions}
|
||||
/>
|
||||
</div>
|
||||
<NH2>加载动画</NH2>
|
||||
<NSwitch
|
||||
|
Loading…
x
Reference in New Issue
Block a user