mirror of
https://github.com/continew-org/continew-admin-ui.git
synced 2025-09-08 22:57:11 +08:00
refactor: 同步 GiDemo 更新
This commit is contained in:
@@ -145,4 +145,12 @@ const isDisabled: Props['cellDisabled'] = (p) => {
|
||||
defineExpose({ formRef })
|
||||
</script>
|
||||
|
||||
<style lang='scss' scoped></style>
|
||||
<style lang='scss' scoped>
|
||||
:deep(.arco-form-item) {
|
||||
margin-bottom: 0;
|
||||
|
||||
.arco-form-item-message {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@@ -1,36 +0,0 @@
|
||||
<template>
|
||||
<div ref="BoxRef" class="gi-flexible-box" :style="style">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { CSSProperties } from 'vue'
|
||||
|
||||
defineOptions({ name: 'GiFlexibleBox' })
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
modelValue: false,
|
||||
direction: 'right',
|
||||
})
|
||||
|
||||
interface Props {
|
||||
modelValue: boolean
|
||||
direction: 'left' | 'right'
|
||||
}
|
||||
|
||||
const BoxRef = ref<HTMLElement | null>()
|
||||
|
||||
const style = computed(() => {
|
||||
const obj: CSSProperties = {}
|
||||
obj[`margin-${props.direction}`]
|
||||
= !props.modelValue && BoxRef.value && BoxRef.value.clientWidth ? `-${BoxRef.value.clientWidth}px` : 0
|
||||
return obj
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.gi-flexible-box {
|
||||
transition: all 0.36s;
|
||||
}
|
||||
</style>
|
120
src/components/GiIconBox/index.vue
Normal file
120
src/components/GiIconBox/index.vue
Normal file
@@ -0,0 +1,120 @@
|
||||
<!--
|
||||
@file GiIconBox 组件 - 图标容器
|
||||
@description 提供可自定义的图标容器,支持不同颜色、尺寸和形状
|
||||
-->
|
||||
<template>
|
||||
<div class="gi-icon-box" :class="getClass" :style="getStyle">
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { type CSSProperties, computed } from 'vue'
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
color: '#165DFF',
|
||||
size: 20,
|
||||
shape: 'square',
|
||||
})
|
||||
|
||||
/** 预设状态颜色 */
|
||||
const STATUS_COLORS = ['primary', 'success', 'warning', 'danger'] as const
|
||||
|
||||
/** 形状类型 */
|
||||
type ShapeType = 'square' | 'round'
|
||||
|
||||
/** 颜色类型 */
|
||||
type ColorType = typeof STATUS_COLORS[number] | string
|
||||
|
||||
/** 组件属性定义 */
|
||||
interface Props {
|
||||
/**
|
||||
* 背景颜色
|
||||
* @description 支持预设状态颜色或自定义颜色值
|
||||
* @default '#165DFF'
|
||||
*/
|
||||
color?: ColorType
|
||||
/**
|
||||
* 容器尺寸
|
||||
* @description 单位为像素
|
||||
* @default 20
|
||||
*/
|
||||
size?: number
|
||||
/**
|
||||
* 容器形状
|
||||
* @description square-方形,round-圆形
|
||||
* @default 'square'
|
||||
*/
|
||||
shape?: ShapeType
|
||||
}
|
||||
|
||||
/** 计算容器的 class */
|
||||
const getClass = computed(() => {
|
||||
const classes = [
|
||||
STATUS_COLORS.includes(props.color as typeof STATUS_COLORS[number])
|
||||
&& `gi-icon-box--${props.color}`,
|
||||
props.shape && `gi-icon-box__shape--${props.shape}`,
|
||||
].filter(Boolean)
|
||||
|
||||
return classes.join(' ')
|
||||
})
|
||||
|
||||
/** 计算容器的样式 */
|
||||
const getStyle = computed((): CSSProperties => {
|
||||
const style: CSSProperties = {}
|
||||
|
||||
// 处理自定义颜色
|
||||
if (!STATUS_COLORS.includes(props.color as typeof STATUS_COLORS[number])) {
|
||||
style.backgroundColor = props.color
|
||||
}
|
||||
|
||||
// 处理自定义尺寸
|
||||
if (props.size !== 20) {
|
||||
style.width = `${props.size}px`
|
||||
style.height = `${props.size}px`
|
||||
}
|
||||
|
||||
return style
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.gi-icon-box {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-shrink: 0;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
color: #fff;
|
||||
transition: all 0.2s ease;
|
||||
|
||||
// 状态颜色
|
||||
&--primary {
|
||||
background-color: rgba(var(--primary-6));
|
||||
}
|
||||
|
||||
&--success {
|
||||
background-color: rgba(var(--success-6));
|
||||
}
|
||||
|
||||
&--warning {
|
||||
background-color: rgba(var(--warning-6));
|
||||
}
|
||||
|
||||
&--danger {
|
||||
background-color: rgba(var(--danger-6));
|
||||
}
|
||||
|
||||
// 形状样式
|
||||
&__shape {
|
||||
&--square {
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
&--round {
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@@ -1,60 +0,0 @@
|
||||
<template>
|
||||
<a-row align="stretch" :gutter="14" class="gi-left-right-pane">
|
||||
<a-col
|
||||
:xs="0" :sm="8" :md="7" :lg="6" :xl="5" :xxl="4" flex="260px" v-bind="props.leftColProps"
|
||||
class="h-full overflow-hidden"
|
||||
>
|
||||
<div class="gi-left-right-pane__left">
|
||||
<slot name="left"></slot>
|
||||
</div>
|
||||
</a-col>
|
||||
|
||||
<a-col
|
||||
:xs="24" :sm="16" :md="17" :lg="18" :xl="19" :xxl="20" flex="1" v-bind="props.rightColProps"
|
||||
class="h-full overflow-hidden"
|
||||
>
|
||||
<div class="gi-left-right-pane__right">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</template>
|
||||
|
||||
<script lang='ts' setup>
|
||||
import type { ColProps } from '@arco-design/web-vue'
|
||||
|
||||
interface Props {
|
||||
leftColProps?: ColProps
|
||||
rightColProps?: ColProps
|
||||
}
|
||||
|
||||
defineOptions({ name: 'GiLeftRightPane' })
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
leftColProps: () => ({}),
|
||||
rightColProps: () => ({}),
|
||||
})
|
||||
|
||||
// 一般用于左树右表结构页面
|
||||
|
||||
defineSlots<{
|
||||
left: () => void
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<style lang='scss' scoped>
|
||||
.gi-left-right-pane {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
padding: $margin;
|
||||
box-sizing: border-box;
|
||||
|
||||
&__left,
|
||||
&__right {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
</style>
|
@@ -1,32 +0,0 @@
|
||||
<template>
|
||||
<a-overflow-list v-if="data.length">
|
||||
<a-tag v-for="(item, index) in data" :key="index" size="small">
|
||||
{{ item }}
|
||||
</a-tag>
|
||||
<template #overflow="{ number }">
|
||||
<a-popover :content-style="{ maxWidth: '300px', padding: '8px 12px' }">
|
||||
<a-tag color="arcoblue" size="small">+{{ number }}</a-tag>
|
||||
<template #content>
|
||||
<a-space wrap>
|
||||
<a-tag v-for="tag in data.filter((i, n) => n >= data.length - number)" :key="tag" size="small">
|
||||
{{ tag }}
|
||||
</a-tag>
|
||||
</a-space>
|
||||
</template>
|
||||
</a-popover>
|
||||
</template>
|
||||
</a-overflow-list>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
defineOptions({ name: 'GiOverFlowTags' })
|
||||
|
||||
withDefaults(defineProps<Props>(), {
|
||||
data: () => [],
|
||||
})
|
||||
interface Props {
|
||||
data: string[]
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss"></style>
|
134
src/components/GiPageLayout/index.vue
Normal file
134
src/components/GiPageLayout/index.vue
Normal file
@@ -0,0 +1,134 @@
|
||||
<template>
|
||||
<a-row align="stretch" :gutter="rowGutter" class="gi-page-layout" :class="getClass">
|
||||
<a-col v-if="slots.left" v-bind="props.leftColProps" :xs="0" :sm="8" :md="7" :lg="6" :xl="5" :xxl="4" flex="260px">
|
||||
<div class="gi-page-layout__left" :style="props.leftStyle">
|
||||
<slot name="left"></slot>
|
||||
</div>
|
||||
</a-col>
|
||||
<a-col :xs="24" :sm="16" :md="17" :lg="18" :xl="19" :xxl="20" flex="1" v-bind="props.rightColProps">
|
||||
<div v-if="slots.header" class="gi-page-layout__header" :style="props.headerStyle">
|
||||
<slot name="header"></slot>
|
||||
</div>
|
||||
<div class="gi-page-layout__body" :style="props.bodyStyle">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</template>
|
||||
|
||||
<script setup lang='ts'>
|
||||
import type { ColProps } from '@arco-design/web-vue'
|
||||
import type { CSSProperties } from 'vue'
|
||||
|
||||
defineOptions({ name: 'GiPageLayout' })
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
margin: true,
|
||||
padding: true,
|
||||
gutter: false,
|
||||
leftColProps: () => ({}),
|
||||
rightColProps: () => ({}),
|
||||
leftStyle: () => ({}),
|
||||
headerStyle: () => ({}),
|
||||
bodyStyle: () => ({}),
|
||||
})
|
||||
|
||||
/** 组件插槽定义 */
|
||||
defineSlots<{
|
||||
header: () => void
|
||||
left: () => void
|
||||
default: () => void
|
||||
}>()
|
||||
|
||||
const getClass = computed(() => {
|
||||
return {
|
||||
'gi-page-layout--margin': props.margin,
|
||||
'gi-page-layout--padding': props.padding,
|
||||
'gi-page-layout--gutter': !!props.gutter,
|
||||
}
|
||||
})
|
||||
|
||||
const rowGutter = computed(() => {
|
||||
if (typeof props.gutter === 'boolean') {
|
||||
return props.gutter ? 14 : undefined
|
||||
}
|
||||
return props.gutter
|
||||
})
|
||||
|
||||
/** 组件属性定义 */
|
||||
interface Props {
|
||||
margin?: boolean
|
||||
padding?: boolean
|
||||
gutter?: boolean | number
|
||||
leftColProps?: ColProps
|
||||
rightColProps?: ColProps
|
||||
leftStyle?: CSSProperties
|
||||
headerStyle?: CSSProperties
|
||||
bodyStyle?: CSSProperties
|
||||
}
|
||||
|
||||
const slots = useSlots()
|
||||
</script>
|
||||
|
||||
<style lang='scss' scoped>
|
||||
.gi-page-layout {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
background-color: var(--color-bg-1);
|
||||
|
||||
&--margin {
|
||||
margin: $margin;
|
||||
}
|
||||
|
||||
&--padding {
|
||||
|
||||
.gi-page-layout__left,
|
||||
.gi-page-layout__header,
|
||||
.gi-page-layout__body {
|
||||
padding: $padding;
|
||||
}
|
||||
|
||||
.gi-page-layout__header {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&--gutter {
|
||||
.gi-page-layout__body-left {
|
||||
border-right: none;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.arco-col) {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.gi-page-layout__left {
|
||||
height: 100%;
|
||||
border-right: 1px solid var(--color-border);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.gi-page-layout__header {
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.gi-page-layout__body {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
</style>
|
4
src/styles/arco-ui/a-space.less
Normal file
4
src/styles/arco-ui/a-space.less
Normal file
@@ -0,0 +1,4 @@
|
||||
// 修复arco-space-item为空时,仍然显示的问题
|
||||
.arco-space-item:empty {
|
||||
display: none;
|
||||
}
|
3
src/styles/arco-ui/a-tabs.less
Normal file
3
src/styles/arco-ui/a-tabs.less
Normal file
@@ -0,0 +1,3 @@
|
||||
.arco-tabs-nav-extra:not(:empty) {
|
||||
margin-right: var(--padding);
|
||||
}
|
@@ -15,6 +15,8 @@
|
||||
@import './a-typography.less';
|
||||
@import './a-button.less';
|
||||
@import './a-divider.less';
|
||||
@import './a-space.less';
|
||||
@import './a-tabs.less';
|
||||
|
||||
@color-menu-dark-bg: var(--color-bg-1);
|
||||
@card-color-bg: var(--color-bg-1);
|
||||
@@ -71,4 +73,4 @@ body {
|
||||
.danger {
|
||||
color: rgb(var(--danger-6));
|
||||
margin-right: 4px;
|
||||
}
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
@use './var.scss' as *;
|
||||
@import './var.scss';
|
||||
|
||||
body {
|
||||
--margin: 14px; // 通用外边距
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/* 全局样式 */
|
||||
@use './var.scss' as *;
|
||||
@import './var.scss';
|
||||
|
||||
.w-full {
|
||||
width: 100%;
|
||||
@@ -162,6 +162,26 @@
|
||||
border-radius: 100px;
|
||||
}
|
||||
|
||||
.gi_bg_1 {
|
||||
background-color: var(--color-bg-1);
|
||||
}
|
||||
|
||||
.gi_bg_2 {
|
||||
background-color: var(--color-bg-2);
|
||||
}
|
||||
|
||||
.gi_bg_3 {
|
||||
background-color: var(--color-bg-3);
|
||||
}
|
||||
|
||||
.gi_bg_4 {
|
||||
background-color: var(--color-bg-4);
|
||||
}
|
||||
|
||||
.gi_bg_5 {
|
||||
background-color: var(--color-bg-5);
|
||||
}
|
||||
|
||||
// hover按钮
|
||||
.gi_hover_btn {
|
||||
border: 0 !important;
|
||||
@@ -211,6 +231,24 @@
|
||||
}
|
||||
}
|
||||
|
||||
// 页面卡片,右侧有返回按钮
|
||||
.gi_page_card {
|
||||
flex: 1;
|
||||
margin: var(--margin);
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.arco-card-body {
|
||||
flex: 1;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
// 卡片标题,标题左侧的伪类样式
|
||||
.gi_card_title {
|
||||
> .arco-card-header {
|
||||
@@ -310,6 +348,26 @@
|
||||
}
|
||||
}
|
||||
|
||||
.gi_full_tabs {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.arco-tabs-content {
|
||||
flex: 1;
|
||||
padding-top: 0;
|
||||
|
||||
.arco-tabs-content-list {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.arco-tabs-pane {
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 编辑表格,表头的必填红色星号
|
||||
.gi_column_require {
|
||||
.arco-table-th-title {
|
||||
@@ -321,6 +379,14 @@
|
||||
}
|
||||
}
|
||||
|
||||
.gi_full_column {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.gi_tabs {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
@@ -1,17 +1,17 @@
|
||||
// 基础样式
|
||||
@use './base.scss' as *;
|
||||
@import './base.scss';
|
||||
|
||||
// 全局类名样式
|
||||
@use './global.scss' as *;
|
||||
@import './global.scss';
|
||||
|
||||
// 自定义原生滚动条样式
|
||||
@use './scrollbar-reset.scss' as *;
|
||||
@import './scrollbar-reset.scss';
|
||||
|
||||
// 自定义 nprogress 插件进度条颜色
|
||||
@use './nprogress.scss' as *;
|
||||
@import './nprogress.scss';
|
||||
|
||||
// 富文本的css主题颜色变量
|
||||
@use './editor.scss' as *;
|
||||
@import './editor.scss';
|
||||
|
||||
// 动画类名
|
||||
@use './animated.scss' as *;
|
||||
@import './animated.scss';
|
||||
|
5
src/types/components.d.ts
vendored
5
src/types/components.d.ts
vendored
@@ -25,15 +25,14 @@ declare module 'vue' {
|
||||
GiCodeView: typeof import('./../components/GiCodeView/index.vue')['default']
|
||||
GiDot: typeof import('./../components/GiDot/index.tsx')['default']
|
||||
GiEditTable: typeof import('./../components/GiEditTable/GiEditTable.vue')['default']
|
||||
GiFlexibleBox: typeof import('./../components/GiFlexibleBox/index.vue')['default']
|
||||
GiFooter: typeof import('./../components/GiFooter/index.vue')['default']
|
||||
GiForm: typeof import('./../components/GiForm/src/GiForm.vue')['default']
|
||||
GiIconBox: typeof import('./../components/GiIconBox/index.vue')['default']
|
||||
GiIconSelector: typeof import('./../components/GiIconSelector/index.vue')['default']
|
||||
GiIframe: typeof import('./../components/GiIframe/index.vue')['default']
|
||||
GiLeftRightPane: typeof import('./../components/GiLeftRightPane/index.vue')['default']
|
||||
GiOption: typeof import('./../components/GiOption/index.vue')['default']
|
||||
GiOptionItem: typeof import('./../components/GiOptionItem/index.vue')['default']
|
||||
GiOverFlowTags: typeof import('./../components/GiOverFlowTags/index.vue')['default']
|
||||
GiPageLayout: typeof import('./../components/GiPageLayout/index.vue')['default']
|
||||
GiSpace: typeof import('./../components/GiSpace/index.vue')['default']
|
||||
GiSplitButton: typeof import('./../components/GiSplitButton/index.vue')['default']
|
||||
GiSplitPane: typeof import('./../components/GiSplitPane/index.vue')['default']
|
||||
|
@@ -1,22 +1,31 @@
|
||||
<template>
|
||||
<div class="gi_table_page">
|
||||
<a-tabs v-model:active-key="activeKey" type="card-gutter" size="large" @change="change">
|
||||
<a-tabs v-model:active-key="activeKey" size="large" position="left" @change="change">
|
||||
<a-tab-pane key="site">
|
||||
<template #title><icon-apps /> 网站配置</template>
|
||||
<keep-alive>
|
||||
<component :is="PanMap[activeKey]" />
|
||||
</keep-alive>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="security">
|
||||
<template #title><icon-safe /> 安全配置</template>
|
||||
<keep-alive>
|
||||
<component :is="PanMap[activeKey]" />
|
||||
</keep-alive>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="mail">
|
||||
<template #title><icon-email /> 邮件配置</template>
|
||||
<keep-alive>
|
||||
<component :is="PanMap[activeKey]" />
|
||||
</keep-alive>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="login">
|
||||
<template #title><icon-lock /> 登录配置</template>
|
||||
<keep-alive>
|
||||
<component :is="PanMap[activeKey]" />
|
||||
</keep-alive>
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
<keep-alive>
|
||||
<component :is="PanMap[activeKey]" />
|
||||
</keep-alive>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
Reference in New Issue
Block a user