diff --git a/.eslintrc-auto-import.json b/.eslintrc-auto-import.json index af1083b..9102b68 100644 --- a/.eslintrc-auto-import.json +++ b/.eslintrc-auto-import.json @@ -5,6 +5,8 @@ "ComputedRef": true, "DirectiveBinding": true, "EffectScope": true, + "ElButton": true, + "ElDialog": true, "ExtractDefaultPropTypes": true, "ExtractPropTypes": true, "ExtractPublicPropTypes": true, diff --git a/src/renderer/auto-imports.d.ts b/src/renderer/auto-imports.d.ts index 4d6ea84..cf39582 100644 --- a/src/renderer/auto-imports.d.ts +++ b/src/renderer/auto-imports.d.ts @@ -7,6 +7,8 @@ export {} declare global { const EffectScope: typeof import('vue')['EffectScope'] + const ElButton: typeof import('element-plus/es')['ElButton'] + const ElDialog: typeof import('element-plus/es')['ElDialog'] const computed: typeof import('vue')['computed'] const createApp: typeof import('vue')['createApp'] const customRef: typeof import('vue')['customRef'] diff --git a/src/renderer/src/components/Button/index.ts b/src/renderer/src/components/Button/index.ts new file mode 100644 index 0000000..ad8d554 --- /dev/null +++ b/src/renderer/src/components/Button/index.ts @@ -0,0 +1,10 @@ +/* + * @Author: donghao donghao@supervision.ltd + * @Date: 2025-07-08 09:43:27 + * @LastEditors: donghao donghao@supervision.ltd + * @LastEditTime: 2025-07-08 09:47:01 + * @FilePath: \Robot-Al-Platform-Web\src\renderer\src\components\Button\index.ts + * @Description: + */ +import button from './src/button.tsx' +export const DSButton = button diff --git a/src/renderer/src/components/Button/src/button.scss b/src/renderer/src/components/Button/src/button.scss new file mode 100644 index 0000000..9a39f03 --- /dev/null +++ b/src/renderer/src/components/Button/src/button.scss @@ -0,0 +1,124 @@ +@import url('@/styles/main.scss'); +/* Button/style.css */ +.ds-button { + display: inline-flex; + align-items: center; + justify-content: center; + position: relative; + cursor: pointer; + white-space: nowrap; + outline: none; + border: 1px solid var(--ds-button-border-color); + border-radius: var(--ds-button-border-radius); + height: 32px; + padding: 0 24px; + letter-spacing: 2px; + // font-size: 14px; + // font-weight: 500; + background-color: transparent; + color: var(--ds-color-info); + transition: all 0.3s; +} + +.ds-button:hover { + color: var(--ds-color-primary); + border-color: var(--el-button-hover-border-color); + outline: none; +} + +/*按钮类型 */ +.ds-button--primary { + color: var(--ds-color-info); + background-color: var(--ds-color-primary); + border-color: var(--ds-color-info); + border: 1px solid var(--ds-color-primary); +} +.ds-button--primary:hover { + color: var(--ds-color-info); + background: #66b1ff; + border-color: #66b1ff; +} + +.ds-button--info { + color: var(--ds-clort-text-1); + border-color: var(--ds-button-info-border-color); + background-color: var(--ds-color-info); +} + +.ds-button--info:hover { + color: var(--ds-color-info); + background: #66b1ff; + border-color: #66b1ff; +} + +.ds-button--success { + color: #fff; + background-color: #67c23a; + border-color: #67c23a; +} +.ds-button--success:hover { + background: #85ce61; + border-color: #85ce61; +} + +/*其他类型样式类似... */ + +/* 按钮尺寸 */ +.ds-button--large { + padding: 10px 20px; + font-size: 16px; +} +.ds-button--small { + padding: 6px 12px; + font-size: 12px; +} + +/* 特殊状态 */ +.ds-button--disabled { + cursor: not-allowed; + opacity: 0.6; +} +.ds-button--loading { + cursor: default; +} +.ds-button--block { + display: block; + width: 100%; +} +.ds-button--ghost { + background-color: transparent; +} +.ds-button--plain { + background-color: #fff; +} +.ds-button--round { + border-radius: 20px; +} +.ds-button--circle { + border-radius: 50%; + padding: 8px; +} + +/* 图标样式 */ +.ds-button__icon { + margin-right: 5px; +} +.ds-button__loading-icon { + display: inline-block; + width: 14px; + height: 14px; + margin-right: 5px; + border: 2px solid #ccc; + border-top-color: transparent; + border-radius: 50%; + animation: rotate 1s linear infinite; +} + +@keyframes rotate { + 0% { + transform: rotate(0); + } + 100% { + transform: rotate(360deg); + } +} diff --git a/src/renderer/src/components/Button/src/button.tsx b/src/renderer/src/components/Button/src/button.tsx new file mode 100644 index 0000000..d560c4b --- /dev/null +++ b/src/renderer/src/components/Button/src/button.tsx @@ -0,0 +1,113 @@ +// Button/index.tsx +import { defineComponent, computed, CSSProperties } from 'vue' +import './button.scss' // 导入样式文件 + +//定义按钮类型 +type ButtonType = 'primary' | 'success' | 'warning' | 'danger' | 'info' | 'text' +type ButtonSize = 'large' | 'default' | 'small' +type ButtonShape = 'circle' | 'round' +type ButtonNativeType = 'button' | 'submit' | 'reset' + +// 定义 Props 接口 +interface ButtonProps { + type?: ButtonType + size?: ButtonSize + shape?: ButtonShape + nativeType?: ButtonNativeType + disabled?: boolean + loading?: boolean + plain?: boolean + ghost?: boolean + block?: boolean + icon?: string + onClick?: (e: Event) => void + class?: string + style?: CSSProperties +} + +export default defineComponent({ + name: 'DSButton', + props: { + type: { + type: String as () => ButtonType, + default: 'default' + }, + size: { + type: String as () => ButtonSize, + default: 'default' + }, + shape: String as () => ButtonShape, + nativeType: { + type: String as () => ButtonNativeType, + default: 'button' + }, + disabled: Boolean, + loading: Boolean, + plain: Boolean, + ghost: Boolean, + block: Boolean, + icon: String + }, + + emits: ['click'], + + setup(props, { slots, emit }) { + // 计算按钮类名 + const buttonClasses = computed(() => [ + 'ds-button', + `ds-button--${props.type}`, + `ds-button--${props.size}`, + { + 'ds-button--disabled': props.disabled, + 'ds-button--loading': props.loading, + 'ds-button--plain': props.plain, + 'ds-button--ghost': props.ghost, + 'ds-button--block': props.block, + [`ds-button--${props.shape}`]: props.shape + }, + props.class + ]) + + // 点击事件处理 + const handleClick = (e: Event) => { + if (!props.disabled && !props.loading) { + emit('click', e) + } else { + e.preventDefault() + } + } + + // 渲染图标 + const renderIcon = () => { + if (props.loading) { + return + } + if (props.icon) { + return + } + return null + } + + // 渲染内容 + const renderContent = () => { + return ( + + {renderIcon()} + {slots.default?.()} + + ) + } + + return () => ( + + ) + } +}) diff --git a/src/renderer/src/components/Dialog/index.ts b/src/renderer/src/components/Dialog/index.ts new file mode 100644 index 0000000..b44d9fa --- /dev/null +++ b/src/renderer/src/components/Dialog/index.ts @@ -0,0 +1,2 @@ +import dialog from "./src/dialog"; +export const DSDialog = dialog; \ No newline at end of file diff --git a/src/renderer/src/components/Dialog/src/dialog.scss b/src/renderer/src/components/Dialog/src/dialog.scss new file mode 100644 index 0000000..3a816b0 --- /dev/null +++ b/src/renderer/src/components/Dialog/src/dialog.scss @@ -0,0 +1,27 @@ +/* DsDialog/style.scss */ +.ds-dialog { + &-footer { + display: flex; + gap: 12px; + padding: 10px 0; + + &--horizontal { + flex-direction: row; + justify-content: flex-end; + } + + &--vertical { + flex-direction: column; + align-items: stretch; + + .el-button { + width: 100%; + } + } + } + + &-body { + max-height: 70vh; + overflow-y: auto; + } +} \ No newline at end of file diff --git a/src/renderer/src/components/Dialog/src/dialog.tsx b/src/renderer/src/components/Dialog/src/dialog.tsx new file mode 100644 index 0000000..e0aa4c1 --- /dev/null +++ b/src/renderer/src/components/Dialog/src/dialog.tsx @@ -0,0 +1,176 @@ +// DsDialog/index.tsx + +// 扩展 el-dialog 的属性 +interface DsDialogProps extends Partial { + // 控制显示/隐藏(v-model) + modelValue?: boolean + // 是否显示底部操作栏(默认显示) + showFooter?: boolean + // 是否显示关闭图标 + showClose?: boolean + // 确认按钮文本 + confirmText?: string + // 取消按钮文本 + cancelText?: string + // 标题(支持字符串或函数) + title?: string | (() => JSX.Element) + // 底部按钮排列方向(默认水平) + footerLayout?: 'horizontal' | 'vertical' + // 是否显示确认按钮 + showConfirm?: boolean + // 是否显示取消按钮 + showCancel?: boolean +} + +export default defineComponent({ + name: 'DsDialog', + + props: { + modelValue: Boolean, + showFooter: { + type: Boolean, + default: true + }, + showClose: { + type: Boolean, + default: true + }, + confirmText: { + type: String, + default: '确定' + }, + cancelText: { + type: String, + default: '取消' + }, + title: [String, Function], + footerLayout: { + type: String as () => 'horizontal' | 'vertical', + default: 'horizontal' + }, + showConfirm: { + type: Boolean, + default: true + }, + showCancel: { + type: Boolean, + default: true + }, + // 其他 el-dialog 属性 + width: [String, Number], + top: String, + draggable: Boolean, + closeOnClickModal: Boolean, + closeOnPressEscape: Boolean, + appendToBody: Boolean + }, + + emits: ['update:modelValue', 'confirm', 'cancel', 'close', 'open', 'opened', 'closed'], + + setup(props, { slots, emit }) { + const dialogVisible = ref(props.modelValue || false) + + // 监听v-model变化 + watch( + () => props.modelValue, + (val) => { + dialogVisible.value = val + } + ) + + // 监听内部visible变化并同步到外部 + watch(dialogVisible, (val) => { + emit('update:modelValue', val) + }) + + // 关闭对话框 + const closeDialog = () => { + dialogVisible.value = false + emit('close') + } + + // 确认操作 + const handleConfirm = () => { + emit('confirm') + // 如果父组件没有处理关闭逻辑,则自动关闭 + if (props.showFooter && !emit('confirm').length) { + closeDialog() + } + } + + // 取消操作 + const handleCancel = () => { + emit('cancel') + closeDialog() + } + + // 计算底部按钮类名 + const footerClasses = computed(() => [ + 'ds-dialog-footer', + `ds-dialog-footer--${props.footerLayout}` + ]) + + // 渲染标题 + const renderTitle = () => { + if (slots.title) return slots.title() + if (typeof props.title === 'function') return props.title() + if (props?.title) + return ( +
+

{props.title}243

+
+ ) + return null + } + + // 渲染内容 + const renderContent = () => { + return slots.default ? slots.default() : null + } + + // 渲染底部操作栏 + const renderFooter = () => { + if (!props.showFooter) return null + + return ( +
+ {props.showCancel && {props.cancelText}} + {props.showConfirm && ( + + {props.confirmText} + + )} + {slots.footer?.()} +
+ ) + } + + return () => ( + (dialogVisible.value = val)} + title={props.title} + closeOnClickModal={props.closeOnClickModal !== false} + closeOnPressEscape={props.closeOnPressEscape !== false} + showClose={props.showClose} + draggable={props.draggable} + width={props.width} + top={props.top} + appendToBody={props.appendToBody} + onClose={closeDialog} + onClosed={() => emit('closed')} + onOpen={() => emit('open')} + onOpened={() => emit('opened')} + v-slots={{ + header: slots.header, + default: slots.default || renderContent, + footer: slots.footer || renderFooter + }} + > + {slots.header?.()} + {slots.default?.() || renderContent()} + {slots.footer?.() || renderFooter()} + + ) + } +}) diff --git a/src/renderer/src/components/IsAction/index.ts b/src/renderer/src/components/IsAction/index.ts new file mode 100644 index 0000000..98f00f5 --- /dev/null +++ b/src/renderer/src/components/IsAction/index.ts @@ -0,0 +1,10 @@ +/* + * @Author: donghao donghao@supervision.ltd + * @Date: 2025-07-08 09:43:27 + * @LastEditors: donghao donghao@supervision.ltd + * @LastEditTime: 2025-07-08 09:44:53 + * @FilePath: \Robot-Al-Platform-Web\src\renderer\src\components\IsAction\index.ts + * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + */ +import isAction from './src/isAction' +export const IsAction = isAction diff --git a/src/renderer/src/components/IsAction/src/isAction.scss b/src/renderer/src/components/IsAction/src/isAction.scss new file mode 100644 index 0000000..83b0f8c --- /dev/null +++ b/src/renderer/src/components/IsAction/src/isAction.scss @@ -0,0 +1,16 @@ +.action_model_wrap { + .el-dialog__header { + display: none; + } + .el-dialog__body { + padding: 40px 24px 14px; + } + .model_content_box { + .icon_box { + img { + width: 24px; + height: 24px; + } + } + } +} diff --git a/src/renderer/src/components/IsAction/src/isAction.tsx b/src/renderer/src/components/IsAction/src/isAction.tsx new file mode 100644 index 0000000..5d9128d --- /dev/null +++ b/src/renderer/src/components/IsAction/src/isAction.tsx @@ -0,0 +1,84 @@ +/* + * @Author: donghao donghao@supervision.ltd + * @Date: 2024-08-20 15:31:30 + * @LastEditors: donghao donghao@supervision.ltd + * @LastEditTime: 2025-07-08 09:38:15 + * @FilePath: \Robot-Al-Platform-Web\src\renderer\src\components\IsAction\isAction.tsx + * @Description: 是否操作行为 + */ +// import { defineComponent, PropType } from "vue"; +// import { ElDialog, ElButton } from "element-plus"; +import warnIcon from '@/assets/common/warn_icon.png' +import './isAction.scss' +export default defineComponent({ + name: 'IsDelete', + props: { + title: { + type: String as PropType, + default: '提示' + }, + message: { + type: String as PropType, + default: '确定要操作吗?' + }, + visible: { + type: Boolean as PropType + // required: true + } + }, + emits: ['update:visible', 'confirm'], + setup(props, { emit }) { + const { visible } = toRefs(props) + const localVisible = ref(visible.value) + const handleConfirm = () => { + emit('confirm') + // visible.value = false; + // emit("update:visible", false); + } + + const handleCancel = () => { + // localVisible.value = false; + emit('update:visible', false) + } + + const handleClose = () => { + // localVisible.value = false; + emit('update:visible', false) + // done(); + } + + watch(visible, (newVal) => { + localVisible.value = newVal + }) + + return () => ( + ( + <> + 取消 + + 确认 + + + ) + }} + > +
+
+ + {props.title} +
+
+ +
+
+
+ ) + } +}) diff --git a/src/renderer/src/styles/base.scss b/src/renderer/src/styles/base.scss index 5ed6406..6020dd2 100644 --- a/src/renderer/src/styles/base.scss +++ b/src/renderer/src/styles/base.scss @@ -1,35 +1,5 @@ -:root { - --ev-c-white: #ffffff; - --ev-c-white-soft: #f8f8f8; - --ev-c-white-mute: #f2f2f2; - --ev-c-black: #1b1b1f; - --ev-c-black-soft: #222222; - --ev-c-black-mute: #282828; - - --ev-c-gray-1: #515c67; - --ev-c-gray-2: #414853; - --ev-c-gray-3: #32363f; - - --ev-c-text-1: rgba(255, 255, 245, 0.86); - --ev-c-text-2: rgba(235, 235, 245, 0.6); - --ev-c-text-3: rgba(235, 235, 245, 0.38); - - --ev-button-alt-border: transparent; - --ev-button-alt-text: var(--ev-c-text-1); - --ev-button-alt-bg: var(--ev-c-gray-3); - --ev-button-alt-hover-border: transparent; - --ev-button-alt-hover-text: var(--ev-c-text-1); - --ev-button-alt-hover-bg: var(--ev-c-gray-2); -} - -:root { - --color-background: var(--ev-c-black); - --color-background-soft: var(--ev-c-black-soft); - --color-background-mute: var(--ev-c-black-mute); - - --color-text: var(--ev-c-text-1); -} +@import url("./global.scss"); *, *::before, @@ -45,8 +15,8 @@ ul { body { min-height: 100vh; - color: var(--color-text); - background: var(--color-background); + color: var(--ds-color-info); + background: var(--ds-background-color); line-height: 1.6; font-family: Inter, diff --git a/src/renderer/src/styles/element-plus.scss b/src/renderer/src/styles/element-plus.scss index 5de605c..92bf265 100644 --- a/src/renderer/src/styles/element-plus.scss +++ b/src/renderer/src/styles/element-plus.scss @@ -1,30 +1,12 @@ @import url('element-plus/dist/index.css'); @import url('element-plus/theme-chalk/dark/css-vars.css'); // 暗黑主题 - -body { - // color: #fff; -} +@import url('@/styles/base.scss'); +@import url('@/styles/global.scss'); // 重置主题色变量 -:root { - --el-color-primary: #154ddd; // 主色调 - // --el-fill-color-blank: transparent; // 背景色 +* { + --el-color-primary: var(--ds-color-primary); // 主色调 } /* button */ -.el-button--default { - --el-button-text-color: #fff; - --el-fill-color-blank: transparent; // 背景色 -} -.el-button--default:hover { - --el-button-hover-bg-color: transparent; // 按钮悬浮背景色 - --el-button-hover-border-color: var(--el-color-primary); // 按钮悬浮边框颜色 - --el-button-hover-text-color: var(--el-color-primary); -} - -.el-button--primary:hover { - --el-button-hover-bg-color: var(--el-color-primary); // 按钮悬浮背景色 - --el-button-hover-border-color: var(--el-color-primary); // 按钮悬浮边框颜色 - --el-button-hover-text-color: var(--el-color-primary); -} .el-button--info { --el-button-bg-color: var(--el-color-info); // --el-button-border-color: var(--el-color-info); @@ -40,53 +22,19 @@ body { // --el-button-disabled-bg-color: var(--el-color-info-light-5); // --el-button-disabled-border-color: var(--el-color-info-light-5); } -.el-button--info:hover { -} - -.el-button, -.el-button.is-round { - padding-left: 26px; - padding-right: 26px; -} -.el-button + .el-button { - margin-left: 8px; -} - -// .el-button:hover { -// background-color: var(--el-button-hover-bg-color); -// border-color: var(--el-button-hover-border-color); -// color: var(--el-button-hover-text-color); -// outline: none; -// } /* form */ .el-form-item__label { - --el-text-color-regular: #fff; // 表单字体颜色 + color: var(--ds-color-info); // 表单字体颜色 } -.el-form-item__content{ - color: #fff; +.el-form-item__content { + color: var(--ds-color-info); } .el-input { - --el-input-text-color: #fff; // 字体颜色 + --el-input-text-color: var(--ds-color-info); // 字体颜色 --el-input-bg-color: transparent; // 背景颜色 } -// .el-input__wrapper { -// align-items: center; -// background-color: var(--el-input-bg-color, var(--el-fill-color-blank)); -// background-image: none; -// border-radius: var(--el-input-border-radius, var(--el-border-radius-base)); -// box-shadow: 0 0 0 1px var(--el-input-border-color, var(--el-border-color)) inset; -// cursor: text; -// display: inline-flex -// ; -// flex-grow: 1; -// justify-content: center; -// padding: 1px 11px; -// transform: translateZ(0); -// transition: var(--el-transition-box-shadow); -// } - .el-form-item--default { margin-bottom: 12px; } @@ -101,23 +49,35 @@ body { .el-dialog { --el-dialog-padding-primary: 0; // 弹窗内边距 } -.el-dialog__footer { - --el-dialog-padding-primary: 0; // 弹窗内边距 -} -.el-dialog__headerbtn { - width: 68px; - height: 54px; - .el-dialog__close { - font-size: 20px; - } -} -.el-dialog__header { - height: 54px; -} -.design-dialog { + +.ds-dialog { padding: 0 !important; overflow: hidden; .el-dialog__header { - background-color: var(--el-color-primary); + background-color: var(--ds-color-primary); + .el-dialog__title{ + color: var(--ds-color-info); + line-height: var(--ds-dialog-header-height); + padding-left: var(--ds-dialog-header-padding); + } + } + + .el-dialog__footer { + --el-dialog-padding-primary: 0; // 弹窗内边距 + } + .el-dialog__headerbtn, + .el-dialog__headerbtn:hover { + width: 68px; + height: var(--ds-dialog-header-height); + .ds-dialog-header { + height: var(--ds-dialog-header-height); + } + .el-dialog__close { + font-size: 20px; + color: var(--ds-color-info); + } + } + .el-dialog__header { + height: var(--ds-dialog-header-height); } } diff --git a/src/renderer/src/styles/global.scss b/src/renderer/src/styles/global.scss index e69de29..14002f4 100644 --- a/src/renderer/src/styles/global.scss +++ b/src/renderer/src/styles/global.scss @@ -0,0 +1,20 @@ +:root { + --ds-color-primary: rgb(21, 77, 221); // 主色调 + --ds-color-primary-light-3: rgba(21, 77, 221, 0.3); + --ds-color-primary-light-5: rgba(21, 77, 221, 0.5); + --ds-color-primary-light-7: rgba(21, 77, 221, 0.7); + --ds-color-primary-light-8: rgba(21, 77, 221, 0.8); + --ds-color-primary-light-9: rgba(21, 77, 221, 0.9); + --ds-color-info: #fff; // 信息色 + --ds-color-text: #fff; // 文本色0 + --ds-clort-text-1: #333; // 文本色1 + --ds-clort-text-2: #666; // 文本色2 + --ds-clort-text-3: #999; // 文本色3 + --ds-button-border-radius: 2px; + --ds-button-border-color: #c9cdd4; + --ds-button-info-border-color: #dcdcdc; + --ds-background-color: #363940; // 背景色 + --ds-dialog-background-color: #363940; // 背景色 + --ds-dialog-header-padding: 24px; // 背景色 + --ds-dialog-header-height: 54px; // 背景色 +} diff --git a/src/renderer/src/styles/main.scss b/src/renderer/src/styles/main.scss index 964cd92..446ff86 100644 --- a/src/renderer/src/styles/main.scss +++ b/src/renderer/src/styles/main.scss @@ -1,4 +1,4 @@ -@import url("./global.scss"); @import url("./base.scss"); +@import url("./global.scss"); @import url("./element-plus.scss"); @import url("./design.scss"); \ No newline at end of file diff --git a/src/renderer/src/views/Design/Settings/01.txt b/src/renderer/src/views/Design/Settings/01.txt new file mode 100644 index 0000000..9c373c5 --- /dev/null +++ b/src/renderer/src/views/Design/Settings/01.txt @@ -0,0 +1,49 @@ + + +
+ + + + + + + + + + + + +
+ +
\ No newline at end of file diff --git a/src/renderer/src/views/Design/Settings/permission.vue b/src/renderer/src/views/Design/Settings/permission.vue index 61af8f2..093be14 100644 --- a/src/renderer/src/views/Design/Settings/permission.vue +++ b/src/renderer/src/views/Design/Settings/permission.vue @@ -2,7 +2,7 @@ * @Author: donghao donghao@supervision.ltd * @Date: 2025-07-04 10:36:19 * @LastEditors: donghao donghao@supervision.ltd - * @LastEditTime: 2025-07-07 17:29:54 + * @LastEditTime: 2025-07-08 13:55:21 * @FilePath: \Robot-Al-Platform-Web\src\renderer\src\views\Design\Settings\permission.vue * @Description: 权限设置 3、完善交互效果 @@ -24,14 +24,14 @@
- 导入 + + 保存 + - 导出 + + 导出 +
@@ -41,7 +41,7 @@
- 修改密码 + 修改密码 @@ -56,7 +56,7 @@ /> - 配置 + 配置 @@ -76,18 +76,13 @@
- -
-
+ - -
- - - +
-
+