feat: 样式优化

This commit is contained in:
dataeaseShu
2025-05-23 16:02:27 +08:00
parent e279ae4a36
commit 437438700c
18 changed files with 303 additions and 213 deletions
+1 -1
View File
@@ -6,7 +6,7 @@ yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
components.d.ts
node_modules
dist
dist-ssr
+2 -2
View File
@@ -6,6 +6,6 @@
// biome-ignore lint: disable
export {}
declare global {
const ElMessage: typeof import('element-plus/es')['ElMessage']
const ElMessageBox: typeof import('element-plus/es')['ElMessageBox']
const ElMessage: typeof import('element-plus-secondary/es')['ElMessage']
const ElMessageBox: typeof import('element-plus-secondary/es')['ElMessageBox']
}
+2 -2
View File
@@ -24,12 +24,12 @@
"@vue/tsconfig": "^0.7.0",
"axios": "^1.8.4",
"crypto-js": "^4.2.0",
"element-plus": "^2.9.7",
"element-plus-secondary": "^1.0.0",
"less": "^4.3.0",
"pinia": "^3.0.2",
"typescript": "~5.7.2",
"unplugin-auto-import": "^19.1.2",
"unplugin-vue-components": "^28.5.0",
"unplugin-vue-components-secondary": "^0.24.6",
"vite": "^6.3.1",
"vite-plugin-svg-icons": "^2.0.1",
"vite-svg-loader": "^5.1.0",
+1 -1
View File
@@ -1,5 +1,5 @@
import { h } from 'vue'
import { ElIcon } from 'element-plus'
import { ElIcon } from 'element-plus-secondary'
import Icon from './src/Icon.vue'
const hIcon = (name: string) => {
return h(ElIcon, null, {
@@ -0,0 +1,11 @@
<template>
<div class="single-page_layout">
<router-view />
</div>
</template>
<style lang="less" scoped>
.single-page_layout {
width: 100vw;
height: 100vh;
}
</style>
+6 -6
View File
@@ -225,13 +225,13 @@ onMounted(() => {
overflow: hidden;
.workspace-select {
width: 100% !important;
:deep(.el-select__wrapper) {
:deep(.ed-select__wrapper) {
border-radius: 10px;
box-shadow: none !important;
background-color: #f1f3f4;
line-height: 32px;
min-height: 48px;
.el-select__selected-item {
.ed-select__selected-item {
height: 32px;
}
.workspace-label {
@@ -308,7 +308,7 @@ onMounted(() => {
display: flex;
column-gap: 4px;
align-items: center;
.el-avatar {
.ed-avatar {
background-color: var(--el-color-primary);
color: #fff;
}
@@ -330,7 +330,7 @@ onMounted(() => {
line-height: 54px;
.workspace-select {
width: 100% !important;
:deep(.el-select__wrapper) {
:deep(.ed-select__wrapper) {
border-radius: 10px;
box-shadow: none !important;
background-color: #f1f3f4;
@@ -416,7 +416,7 @@ onMounted(() => {
display: flex;
column-gap: 4px;
align-items: center;
.el-avatar {
.ed-avatar {
background-color: var(--el-color-primary);
color: #fff;
}
@@ -467,7 +467,7 @@ onMounted(() => {
border-right: 1px solid var(--el-menu-border-color);
border-radius: 0;
background-color: var(--white);
:deep(.el-menu) {
:deep(.ed-menu) {
border: none;
}
}
+77 -70
View File
@@ -1,112 +1,119 @@
import { createRouter, createWebHashHistory } from 'vue-router'
import { createRouter, createWebHashHistory } from "vue-router";
import Layout from '@/components/layout/index.vue'
import login from '@/views/login/index.vue'
import chat from '@/views/chat/index.vue'
import ds from '@/views/ds/index.vue'
import DashboardEditor from '@/views/dashboard/editor/index.vue'
import Dashboard from '@/views/dashboard/index.vue'
import setting from '@/views/setting/index.vue'
import { watchRouter } from './watch'
import Layout from "@/components/layout/index.vue";
import SinglePage from "@/components/layout/SinglePage.vue";
import login from "@/views/login/index.vue";
import chat from "@/views/chat/index.vue";
import ds from "@/views/ds/index.vue";
import DashboardEditor from "@/views/dashboard/editor/index.vue";
import Dashboard from "@/views/dashboard/index.vue";
import setting from "@/views/setting/index.vue";
import { watchRouter } from "./watch";
const router = createRouter({
history: createWebHashHistory(),
routes: [
{
path: '/login',
name: 'login',
component: login
path: "/login",
name: "login",
component: login,
},
{
path: '/chat',
path: "/chat",
component: Layout,
redirect: '/chat/index',
redirect: "/chat/index",
children: [
{
path: 'index',
name: 'chat',
path: "index",
name: "chat",
component: chat,
meta: { title: 'Data Q&A', icon: 'chat' }
}
]
meta: { title: "Data Q&A", icon: "chat" },
},
],
},
{
path: '/ds',
component: Layout,
redirect: '/ds/index',
path: "/dsTable",
component: SinglePage,
children: [
{
path: 'index',
name: 'ds',
path: ":dsId/:dsName",
name: "dsTable",
component: () => import("@/views/ds/TableList.vue"),
props: true,
},
],
},
{
path: "/ds",
component: Layout,
redirect: "/ds/index",
children: [
{
path: "index",
name: "ds",
component: ds,
meta: { title: 'Data Connections', icon: 'ds' }
meta: { title: "Data Connections", icon: "ds" },
},
{
path: 'dsTable/:dsId/:dsName',
name: 'dsTable',
component: () => import('@/views/ds/TableList.vue'),
props: true
}
]
],
},
{
path: '/dashboard',
path: "/dashboard",
component: Layout,
redirect: '/dashboard/index',
redirect: "/dashboard/index",
children: [
{
path: 'index',
name: 'dashboard',
path: "index",
name: "dashboard",
component: Dashboard,
meta: { title: 'Dashboard', icon: 'dashboard' }
}
]
meta: { title: "Dashboard", icon: "dashboard" },
},
],
},
{
path: '/dashboard-edit',
redirect: '/dashboard-edit/index',
path: "/dashboard-edit",
redirect: "/dashboard-edit/index",
component: Layout,
children: [
{
path: 'index',
name: 'dashboard-edit',
path: "index",
name: "dashboard-edit",
component: DashboardEditor,
meta: { title: 'dashboard-edit', icon: 'dashboard' }
}
]
meta: { title: "dashboard-edit", icon: "dashboard" },
},
],
},
{
path: '/setting',
path: "/setting",
component: Layout,
redirect: '/setting/index',
redirect: "/setting/index",
children: [
{
path: 'index',
name: 'setting',
path: "index",
name: "setting",
component: setting,
meta: { title: 'Settings', icon: 'setting' }
}
]
meta: { title: "Settings", icon: "setting" },
},
],
},
{
path: '/system',
path: "/system",
component: Layout,
redirect: '/system/user',
redirect: "/system/user",
children: [
{
path: 'user',
name: 'user',
component: () => import('@/views/system/user/index.vue'),
meta: { title: 'User Management', icon: 'icon_user' }
path: "user",
name: "user",
component: () => import("@/views/system/user/index.vue"),
meta: { title: "User Management", icon: "icon_user" },
},
{
path: 'model',
name: 'model',
component: () => import('@/views/system/model/index.vue'),
meta: { title: 'AI Model Configuration', icon: 'icon_ai' }
}
]
}
]
})
watchRouter(router)
export default router
path: "model",
name: "model",
component: () => import("@/views/system/model/index.vue"),
meta: { title: "AI Model Configuration", icon: "icon_ai" },
},
],
},
],
});
watchRouter(router);
export default router;
+1 -1
View File
@@ -1,4 +1,4 @@
import { ElMessage } from 'element-plus'
import { ElMessage } from 'element-plus-secondary'
import { useCache } from '@/utils/useCache'
const { wsCache } = useCache()
const whiteList = ['/login']
@@ -160,7 +160,7 @@ const isEditMode = computed(() => true)
</template>
<style scoped lang="less">
.el-dropdown-link{
.ed-dropdown-link{
margin-top: 3px !important;
}
+134 -86
View File
@@ -1,35 +1,56 @@
<template>
<div class="layout">
<el-row class="header">
<div class="table-list_layout">
<div class="header">
<div class="title">
<el-button text :icon="ArrowLeft" @click="back()" />
<el-button text style="color: #fff" :icon="ArrowLeft" @click="back()" />
{{ props.dsName }}
</div>
</el-row>
<el-row class="container" :gutter="20">
<el-col :span="4">
<el-button type="primary" @click="save()"> Save </el-button>
</div>
<div class="container">
<div class="left-side">
Tables
<el-input v-model="searchValue" placeholder="Search" />
<el-input
style="margin: 16px 0"
v-model="searchValue"
placeholder="Search"
/>
<div>
<div v-for="item in tableList" class="table-item" @click="clickTable(item)">{{ item.table_name }}</div>
</div>
</el-col>
<el-col :span="20">
<div v-if="fieldList.length === 0">No data, select a table from left</div>
<div v-else>
<div style="display: flex;justify-content: space-between;align-items: center;">
<div style="display: flex;justify-content: start;align-items: center;">
<span>{{ currentTable.table_name }}</span>
<span>&nbsp;|&nbsp;Comment:&nbsp;</span>
<span>
<el-input v-model="currentTable.custom_comment" />
</span>
</div>
<el-button type="primary" @click="save()">
Save
</el-button>
<div
v-for="item in tableList"
class="list-item_primary"
@click="clickTable(item)"
>
{{ item.table_name }}
</div>
<el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick">
</div>
</div>
<div class="right-side">
<div v-if="fieldList.length === 0">
No data, select a table from left
</div>
<div v-else>
<div
style="
display: flex;
justify-content: space-between;
align-items: center;
"
>
<div
style="display: flex; justify-content: start; align-items: center"
>
<span>{{ currentTable.table_name }}</span>
<el-divider direction="vertical" />
<span>Comment:</span>
<el-input style="margin-left: 12px;" v-model="currentTable.custom_comment" />
</div>
</div>
<el-tabs
v-model="activeName"
class="demo-tabs"
@tab-click="handleClick"
>
<el-tab-pane label="Table Schema" name="schema">
<el-table :data="fieldList" style="width: 100%">
<el-table-column prop="field_name" label="Name" width="180" />
@@ -45,111 +66,138 @@
<el-table-column label="Status" width="180">
<template #default="scope">
<div style="display: flex; align-items: center">
<el-switch
v-model="scope.row.checked"
size="small"
/>
<el-switch v-model="scope.row.checked" size="small" />
</div>
</template>
</el-table-column>
</el-table>
</el-tab-pane>
<el-tab-pane label="Preview" name="preview">
<div>Preview 100 items</div>
<el-table :data="previewData.data" style="width: 100%;height: 600px;">
<el-table-column v-for="c in previewData.fields" :prop="c" :label="c"/>
<div style="margin: 16px 0;">Preview 100 items</div>
<el-table
:data="previewData.data"
style="width: 100%; height: 600px"
>
<el-table-column
v-for="c in previewData.fields"
:prop="c"
:label="c"
/>
</el-table>
</el-tab-pane>
</el-tabs>
</div>
</el-col>
</el-row>
</div>
</div>
</div>
</template>
<script lang="tsx" setup>
import { ref } from 'vue'
import { datasourceApi } from '@/api/datasource'
import { onMounted } from 'vue'
import { ArrowLeft } from '@element-plus/icons-vue'
import type { TabsPaneContext } from 'element-plus'
import { ref } from "vue";
import { datasourceApi } from "@/api/datasource";
import { onMounted } from "vue";
import { ArrowLeft } from "@element-plus/icons-vue";
import type { TabsPaneContext } from "element-plus-secondary";
const props = defineProps({
dsId: { type: [Number], required: true },
dsName: { type: [String], required: true }
})
dsName: { type: [String], required: true },
});
const dsId = ref<Number>(0)
const searchValue = ref('')
const tableList = ref<any>([])
const currentTable = ref<any>({})
const fieldList = ref<any>([])
const previewData = ref<any>({})
const dsId = ref<Number>(0);
const searchValue = ref("");
const tableList = ref<any>([]);
const currentTable = ref<any>({});
const fieldList = ref<any>([]);
const previewData = ref<any>({});
const activeName = ref('schema')
const activeName = ref("schema");
const buildData = () => {
return {"table": currentTable.value, "fields": fieldList.value}
}
return { table: currentTable.value, fields: fieldList.value };
};
const back = () => {
history.back()
}
history.back();
};
const save = () => {
datasourceApi.edit(buildData()).then(() => {
ElMessage({
message: 'Save success',
type: 'success',
showClose: true
})
})
}
message: "Save success",
type: "success",
showClose: true,
});
});
};
const clickTable = (table: any) => {
currentTable.value = table
currentTable.value = table;
datasourceApi.fieldList(table.id).then((res) => {
fieldList.value = res
fieldList.value = res;
datasourceApi.previewData(dsId.value, buildData()).then((res) => {
previewData.value = res
})
})
}
previewData.value = res;
});
});
};
const handleClick = (tab: TabsPaneContext) => {
if(tab.paneName === 'preview') {
if (tab.paneName === "preview") {
datasourceApi.previewData(dsId.value, buildData()).then((res) => {
previewData.value = res
})
previewData.value = res;
});
}
}
};
onMounted(() => {
dsId.value = props.dsId
fieldList.value = []
dsId.value = props.dsId;
fieldList.value = [];
datasourceApi.tableList(props.dsId).then((res) => {
tableList.value = res
})
})
tableList.value = res;
});
});
</script>
<style lang="less" scoped>
.layout{
padding: 20px 40px;
.header{
padding: 20px 0;
display: flex;
justify-content: space-between;
}
.title{
.table-list_layout {
width: 100%;
height: 100%;
.header {
height: 56px;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 24px;
background: #050e21;
box-shadow: 0 2px 4px #1f23291f;
}
.container{
height: 100%;
.table-item{
margin: 10px 0;
.title {
color: #fff;
font-family: var(--de-custom_font, "PingFang");
font-size: 16px;
font-weight: 400;
display: flex;
align-items: center;
width: 50%;
position: relative;
}
.container {
height: calc(100% - 56px);
width: 100%;
.left-side {
width: 246px;
height: 100%;
float: left;
border-right: 1px solid #ccc;
padding: 24px;
}
.right-side {
width: calc(100% - 246px);
height: 100%;
float: right;
padding: 24px;
}
}
}
</style>
</style>
+36 -23
View File
@@ -8,17 +8,30 @@
@closed="close"
modal-class="add-datasource_dialog"
>
<el-steps
v-show="isCreate"
style="max-width: 600px"
:active="active"
align-center
>
<el-step title="Base Info" />
<el-step title="Choose Tables" />
</el-steps>
<div v-show="active === 1" class="container">
<el-form :model="form" label-width="auto" ref="dsFormRef" :rules="rules">
<template #header="{ close, titleId, titleClass }">
<div style="display: flex">
<div style="margin-right: 24px">Add Datasource</div>
<el-steps
v-show="isCreate"
:active="active"
align-center
custom
style="max-width: 400px; flex: 1"
>
<el-step title="Base Info" />
<el-step title="Choose Tables" />
</el-steps>
</div>
</template>
<div v-show="active === 0" class="container">
<el-form
:model="form"
label-position="top"
label-width="auto"
ref="dsFormRef"
:rules="rules"
>
<el-form-item label="Name" prop="name">
<el-input v-model="form.name" />
</el-form-item>
@@ -96,7 +109,7 @@
</div>
</el-form>
</div>
<div v-show="active === 2" class="container" v-loading="tableListLoading">
<div v-show="active === 1" class="container" v-loading="tableListLoading">
<el-checkbox-group v-model="checkList" style="position: relative">
<FixedSizeList
:itemSize="40"
@@ -127,16 +140,16 @@
>Test Connect</el-button
>
<el-button
v-show="active === 1 && isCreate"
v-show="active === 0 && isCreate"
type="primary"
@click="next(dsFormRef)"
>Next</el-button
>
<el-button v-show="active === 2 && isCreate" @click="preview"
<el-button v-show="active === 1 && isCreate" @click="preview"
>Preview</el-button
>
<el-button
v-show="active === 2 || !isCreate"
v-show="active === 1 || !isCreate"
type="primary"
@click="save(dsFormRef)"
>Save</el-button
@@ -148,9 +161,9 @@
import { ref, reactive } from "vue";
import { datasourceApi } from "@/api/datasource";
import { encrypted, decrypted } from "./js/aes";
import { ElMessage } from "element-plus";
import type { FormInstance, FormRules } from "element-plus";
import FixedSizeList from "element-plus/es/components/virtual-list/src/components/fixed-size-list.mjs";
import { ElMessage } from "element-plus-secondary";
import type { FormInstance, FormRules } from "element-plus-secondary";
import FixedSizeList from "element-plus-secondary/es/components/virtual-list/src/components/fixed-size-list.mjs";
import { Plus } from "@element-plus/icons-vue";
import { useCache } from "@/utils/useCache";
import { dsType, haveSchema } from "@/views/ds/js/ds-type";
@@ -158,7 +171,7 @@ import { dsType, haveSchema } from "@/views/ds/js/ds-type";
const { wsCache } = useCache();
const dsFormRef = ref<FormInstance>();
const emit = defineEmits(["refresh"]);
const active = ref(1);
const active = ref(0);
const isCreate = ref(true);
const isEditTable = ref(false);
const checkList = ref<any>([]);
@@ -199,7 +212,7 @@ const config = ref<any>({
const close = () => {
dialogVisible.value = false;
isCreate.value = true;
active.value = 1;
active.value = 0;
isEditTable.value = false;
checkList.value = [];
tableList.value = [];
@@ -230,7 +243,7 @@ const open = (item: any, editTable: boolean = false) => {
}
if (editTable) {
active.value = 2;
active.value = 1;
isEditTable.value = true;
isCreate.value = false;
// request tables and check tables
@@ -421,8 +434,8 @@ defineExpose({ open });
.add-datasource_dialog {
.container {
max-height: 600px;
margin-top: 20px;
.el-vl__window.el-select-dropdown__list::-webkit-scrollbar {
overflow-y: auto;
.ed-vl__window.ed-select-dropdown__list::-webkit-scrollbar {
width: 0;
height: 0;
}
+3 -2
View File
@@ -65,7 +65,7 @@ import { ref, onMounted } from 'vue'
import DsForm from './form.vue'
import { datasourceApi } from '@/api/datasource'
import { datetimeFormat } from '@/utils/utils'
import { ElMessageBox } from 'element-plus'
import { ElMessageBox } from 'element-plus-secondary'
import { useRouter } from 'vue-router'
const searchValue = ref<string>('')
@@ -148,7 +148,7 @@ const getTables = (id: number, name: string) => {
// datasourceApi.execSql(id,'select id,name,table_name from core_dataset_table limit 10').then((res) => {
// console.log(res)
// })
router.push(`/ds/dsTable/${id}/${name}`)
router.push(`/dsTable/${id}/${name}`)
}
onMounted(() => {
@@ -263,6 +263,7 @@ onMounted(() => {
display: flex;
.action-btn {
display: none;
min-width: 0;
}
}
:hover .action-btn{
+1 -1
View File
@@ -140,7 +140,7 @@ const submitForm = () => {
}
}
:deep(.el-input__wrapper) {
:deep(.ed-input__wrapper) {
background-color: #f5f7fa;
}
</style>
+5 -5
View File
@@ -262,7 +262,7 @@ onMounted(() => {
}
.sqlbot-table {
border-radius: 6px;
:deep(.el-table) {
:deep(.ed-table) {
--el-table-header-bg-color: #f5f7fa;
--el-table-border-color: #ebeef5;
--el-table-header-text-color: #606266;
@@ -303,19 +303,19 @@ onMounted(() => {
}
.sqlbot-form {
width: 100%;
.el-form-item {
.ed-form-item {
margin-bottom: 16px;
text-align: left;
label {
font-size: 14px;
color: #606266;
}
/* .el-input {
/* .ed-input {
--el-input-border-color: #e5e8ed;
--el-input-border-radius: 4px;
--el-input-inner-height: 40px !important;
}
.el-select {
.ed-select {
--el-select-bg-color: #f5f7fa;
--el-select-border-color: #e5e8ed;
--el-select-border-radius: 4px;
@@ -326,7 +326,7 @@ onMounted(() => {
.sqlbot-dialog {
width: 500px;
:deep(.el-dialog__header) {
:deep(.ed-dialog__header) {
text-align: left !important;
font-size: 16px;
background-color: #f5f7fa;
+3 -3
View File
@@ -43,9 +43,9 @@ const handleClick = (tab: any, event: MouseEvent) => {
box-shadow: var(--shadow);
overflow: hidden;
padding: 24px;
:deep(.el-tabs) {
:deep(.ed-tabs) {
--el-tabs-header-height: 55px;
.el-tabs__header {
.ed-tabs__header {
margin: 0 0 24px !important;
}
}
@@ -63,7 +63,7 @@ const handleClick = (tab: any, event: MouseEvent) => {
height: 28px;
}
}
:deep(.el-tabs__item) {
:deep(.ed-tabs__item) {
padding: 0 16px !important;
&:hover {
// color: var(--primary-color);
+3 -3
View File
@@ -433,7 +433,7 @@ const batchEnableHandler = () => {
}
.sqlbot-table {
border-radius: 6px;
:deep(.el-table) {
:deep(.ed-table) {
--el-table-header-bg-color: #f5f7fa;
--el-table-border-color: #ebeef5;
--el-table-header-text-color: #606266;
@@ -487,7 +487,7 @@ const batchEnableHandler = () => {
}
.sqlbot-form {
width: 100%;
.el-form-item {
.ed-form-item {
margin-bottom: 16px;
text-align: left;
label {
@@ -499,7 +499,7 @@ const batchEnableHandler = () => {
.sqlbot-dialog {
width: 500px;
:deep(.el-dialog__header) {
:deep(.ed-dialog__header) {
text-align: left !important;
font-size: 16px;
background-color: #f5f7fa;
+3 -3
View File
@@ -315,7 +315,7 @@ onMounted(() => {
}
.sqlbot-table {
border-radius: 6px;
:deep(.el-table) {
:deep(.ed-table) {
--el-table-header-bg-color: #f5f7fa;
--el-table-border-color: #ebeef5;
--el-table-header-text-color: #606266;
@@ -369,7 +369,7 @@ onMounted(() => {
}
.sqlbot-form {
width: 100%;
.el-form-item {
.ed-form-item {
margin-bottom: 16px;
text-align: left;
label {
@@ -381,7 +381,7 @@ onMounted(() => {
.sqlbot-dialog {
width: 500px;
:deep(.el-dialog__header) {
:deep(.ed-dialog__header) {
text-align: left !important;
font-size: 16px;
background-color: #f5f7fa;
+13 -3
View File
@@ -1,8 +1,8 @@
import { defineConfig, loadEnv } from 'vite'
import vue from '@vitejs/plugin-vue'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import Components from 'unplugin-vue-components-secondary/vite'
import { ElementPlusResolver } from 'unplugin-vue-components-secondary/resolvers'
import path from 'path'
import svgLoader from 'vite-svg-loader'
export default defineConfig(({ mode }) => {
@@ -38,7 +38,7 @@ export default defineConfig(({ mode }) => {
rollupOptions: {
output: {
manualChunks: {
'element-plus': ['element-plus'],
'element-plus-secondary': ['element-plus-secondary'],
},
},
},
@@ -47,5 +47,15 @@ export default defineConfig(({ mode }) => {
jsxFactory: 'h',
jsxFragment: 'Fragment',
},
server: {
proxy: {
'/api': {
target: 'http://192.168.11.65:8000',
changeOrigin: true,
rewrite: path => path.replace(/^\/api/, '/api')
}
},
port: 8080
}
}
})