瀏覽代碼

feat: 添加数据查询配置

jiaxing.liao 6 天之前
父節點
當前提交
f9a35890e1

+ 4 - 0
apps/web/components.d.ts

@@ -26,6 +26,7 @@ declare module 'vue' {
     ElContainer: typeof import('element-plus/es')['ElContainer']
     ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
     ElDialog: typeof import('element-plus/es')['ElDialog']
+    ElDorpdown: typeof import('element-plus/es')['ElDorpdown']
     ElDrawer: typeof import('element-plus/es')['ElDrawer']
     ElDropdown: typeof import('element-plus/es')['ElDropdown']
     ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
@@ -37,6 +38,7 @@ declare module 'vue' {
     ElHeader: typeof import('element-plus/es')['ElHeader']
     ElIcon: typeof import('element-plus/es')['ElIcon']
     ElInput: typeof import('element-plus/es')['ElInput']
+    ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
     ElMain: typeof import('element-plus/es')['ElMain']
     ElMenu: typeof import('element-plus/es')['ElMenu']
     ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
@@ -45,10 +47,12 @@ declare module 'vue' {
     ElRadio: typeof import('element-plus/es')['ElRadio']
     ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
     ElRow: typeof import('element-plus/es')['ElRow']
+    ElScrollbar: typeof import('element-plus/es')['ElScrollbar']
     ElSelect: typeof import('element-plus/es')['ElSelect']
     ElSplitter: typeof import('element-plus/es')['ElSplitter']
     ElSplitterPanel: typeof import('element-plus/es')['ElSplitterPanel']
     ElSubMenu: typeof import('element-plus/es')['ElSubMenu']
+    ElTab: typeof import('element-plus/es')['ElTab']
     ElTable: typeof import('element-plus/es')['ElTable']
     ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
     ElTabPane: typeof import('element-plus/es')['ElTabPane']

+ 237 - 9
apps/web/src/components/setter/DatabaseSetter.vue

@@ -6,7 +6,10 @@
  * @Describe: 数据设置器
 -->
 <script lang="ts" setup>
-import { Icon } from '@iconify/vue'
+import { computed, ref } from 'vue'
+import { IconButton, Icon } from '@repo/ui'
+import SelectTableModal from '@/features/selectTableModal/index.vue'
+
 const props = withDefaults(
 	defineProps<{
 		data: any
@@ -20,16 +23,241 @@ const props = withDefaults(
 const emit = defineEmits<{
 	'update:visible': [value: boolean]
 }>()
+
+const selectTableModalRef = ref<InstanceType<typeof SelectTableModal> | null>(null)
+// 数据表
+const tableList = ref<any[]>([])
+// 查询字段
+const fieldList = ref<any[]>([])
+// 查询条件
+const conditionList = ref<any[]>([])
+// 排序方式
+const sortList = ref<any[]>([])
+// 查询上限
+const limit = ref<number>(100)
+// 输出
+const outputList = ref<any[]>([])
+
+// 异常处理
+const exceptionConfig = ref<{
+	timeout: number
+	retry: number
+	handler: number
+}>({
+	timeout: 60,
+	retry: 3,
+	handler: 0
+})
+
+const columns = computed(() => {
+	return (tableList.value?.[0]?.columns || []).filter(
+		(item: any) => !fieldList.value.find((field: any) => field.name === item.name)
+	)
+})
+
+const addDatabase = () => {
+	selectTableModalRef.value?.open()
+}
+
+const onAddTable = (table: unknown) => {
+	tableList.value = [table]
+}
 </script>
+
 <template>
-	<div class="w-full">
-		<el-collapse>
-			<el-collapse-item title="数据表" name="1">
-				<el-empty description="暂无数据表配置" :image-size="40" />
+	<el-scrollbar class="w-full">
+		<el-collapse expand-icon-position="left" :model-value="['1', '2', '3', '4', '5', '6', '7']">
+			<el-collapse-item name="1">
+				<template #title="{ isActive }">
+					<div class="flex items-center justify-between">
+						<span>数据表</span>
+						<IconButton
+							size="large"
+							v-show="isActive"
+							icon="iconoir:plus"
+							link
+							@click.stop="addDatabase"
+						/>
+					</div>
+				</template>
+				<template v-for="table in tableList" :key="table">
+					<div
+						class="px-12px flex items-center justify-between cursor-pointer mb-12px p-12px hover:bg-gray-100 border border-solid border-gray-300 rounded-8px"
+					>
+						<div class="left flex items-center gap-24px">
+							<div class="icon w-40px h-40px bg-#ffb800 rounded-md grid place-items-center">
+								<Icon icon="iconoir:database-solid" color="#fff" height="24" width="24" />
+							</div>
+							<div>
+								<div class="text-#333 text-xs">{{ table.name }}</div>
+							</div>
+						</div>
+						<IconButton icon="ep:delete" size="small" />
+					</div>
+					<div class="flex gap-4px">
+						<el-tag
+							v-for="column in table.columns"
+							:key="column.name"
+							effect="light"
+							size="small"
+							>{{ column.name }}</el-tag
+						>
+					</div>
+				</template>
+
+				<el-empty v-if="!tableList.length" description="请添加一个数据表到此处" :image-size="40" />
+			</el-collapse-item>
+
+			<el-collapse-item name="2">
+				<template #title="{ isActive }">
+					<div class="flex items-center justify-between">
+						<span>查询字段查询字段</span>
+						<el-dropdown popper-class="w-200px" placement="bottom-end">
+							<IconButton size="large" v-show="isActive" icon="iconoir:plus" link @click.stop />
+							<template #dropdown>
+								<el-dropdown-item
+									v-for="column in columns"
+									:key="column.name"
+									@click="fieldList.push(column)"
+									>{{ column.name }}</el-dropdown-item
+								>
+							</template>
+						</el-dropdown>
+					</div>
+				</template>
+				<div v-for="field in fieldList" :key="field.name" class="flex gap-4px mb-12px">
+					<span>{{ field.name }}</span>
+					<el-tag effect="light">{{ field.type }}</el-tag>
+				</div>
+				<el-empty v-if="!fieldList.length" description="请添加查询字段" :image-size="40" />
+			</el-collapse-item>
+
+			<el-collapse-item title="查询条件" name="3"> </el-collapse-item>
+
+			<el-collapse-item name="5">
+				<template #title="{ isActive }">
+					<div class="flex items-center justify-between">
+						<span>排序方式</span>
+						<el-dropdown popper-class="w-200px" placement="bottom-end">
+							<IconButton size="large" v-show="isActive" icon="iconoir:plus" link @click.stop />
+							<template #dropdown>
+								<el-dropdown-item
+									v-for="column in fieldList"
+									:key="column.name"
+									@click="
+										sortList.push({
+											name: column.name,
+											type: column.type,
+											sort: 'asc'
+										})
+									"
+									>{{ column.name }}</el-dropdown-item
+								>
+							</template>
+						</el-dropdown>
+					</div>
+				</template>
+				<div v-for="field in sortList" :key="field.name" class="flex items-center gap-4px mb-12px">
+					<div class="flex-1 flex justify-between">
+						<span>{{ field.name }}</span>
+						<el-tag effect="light">{{ field.type }}</el-tag>
+					</div>
+					<el-select style="width: 120px" v-model="field.sort" placeholder="请选择">
+						<el-option label="升序" value="asc"></el-option>
+						<el-option label="降序" value="desc"></el-option>
+					</el-select>
+				</div>
+				<el-empty v-if="!sortList.length" description="请添加排序字段" :image-size="40" />
+			</el-collapse-item>
+
+			<el-collapse-item title="查询上限" name="6">
+				<el-input-number
+					v-model="limit"
+					:min="1"
+					:max="1000"
+					style="width: 100%"
+					controls-position="right"
+					placeholder="请输入查询上限"
+				/>
+			</el-collapse-item>
+
+			<el-collapse-item title="输出" name="7">
+				<el-collapse-item name="7-1">
+					<template #title="{ isActive }">
+						<div class="flex items-center justify-between">
+							<span>outputList</span>
+							<el-dropdown popper-class="w-200px" placement="bottom-end">
+								<IconButton size="large" v-show="isActive" icon="iconoir:plus" link @click.stop />
+								<template #dropdown>
+									<el-dropdown-item
+										v-for="column in fieldList"
+										:key="column.name"
+										@click="
+											outputList.push({
+												name: column.name,
+												type: column.type
+											})
+										"
+										>{{ column.name }}</el-dropdown-item
+									>
+								</template>
+							</el-dropdown>
+						</div>
+					</template>
+					<div
+						v-for="field in outputList"
+						:key="field.name"
+						class="flex items-center gap-4px mb-12px"
+					>
+						<span>{{ field.name }}</span>
+						<el-tag effect="light">{{ field.type }}</el-tag>
+					</div>
+				</el-collapse-item>
+			</el-collapse-item>
+
+			<el-collapse-item title="异常处理" name="8">
+				<el-form>
+					<el-row>
+						<el-col :span="8">
+							<el-form-item label="超时时间">
+								<el-input-number
+									v-model="exceptionConfig.timeout"
+									:min="1"
+									:max="1000"
+									style="width: 100%"
+									controls-position="right"
+									placeholder="请输入"
+									suffix="s"
+								/>
+							</el-form-item>
+						</el-col>
+						<el-col :span="8">
+							<el-form-item label="重试次数">
+								<el-input-number
+									v-model="exceptionConfig.retry"
+									:min="0"
+									:max="5"
+									style="width: 100%"
+									controls-position="right"
+									placeholder="请输入"
+									suffix="s"
+								/>
+							</el-form-item>
+						</el-col>
+						<el-col :span="8">
+							<el-form-item label="异常处理方式">
+								<el-select v-model="exceptionConfig.handler" placeholder="请选择">
+									<el-option label="中断流程" :value="0" />
+									<el-option label="返回设定内容" :value="1" />
+									<el-option label="执行异常流程" :value="2" />
+								</el-select>
+							</el-form-item>
+						</el-col>
+					</el-row>
+				</el-form>
 			</el-collapse-item>
-			<el-collapse-item title="输出" name="2"> </el-collapse-item>
-			<el-collapse-item title="异常处理" name="3"> </el-collapse-item>
 		</el-collapse>
-	</div>
+	</el-scrollbar>
+
+	<SelectTableModal ref="selectTableModalRef" @add="onAddTable" />
 </template>
-<style lang="less" scoped></style>

+ 7 - 2
apps/web/src/components/setter/index.vue

@@ -112,12 +112,17 @@ const closeDrawer = () => {
 	.drawer .content {
 		flex: 1;
 		// padding: 16px;
-		// overflow-y: auto;
+		overflow-y: auto;
 	}
 
-	::v-deep(.el-collapse-item__header, .el-collapse-item__content) {
+	::v-deep(.el-collapse-item__header) {
 		box-sizing: border-box;
 		padding: 0 8px;
 	}
+	::v-deep(.el-collapse-item__content) {
+		box-sizing: border-box;
+		padding: 0 8px;
+		padding-bottom: 12px;
+	}
 }
 </style>

+ 115 - 0
apps/web/src/features/selectTableModal/index.vue

@@ -0,0 +1,115 @@
+<template>
+	<el-dialog
+		v-model="visible"
+		append-to-body="body"
+		title="选择数据表"
+		:width="1000"
+		body-class="h-400px"
+	>
+		<div class="w-full h-full flex">
+			<div class="w-200px">
+				<el-menu class="w-200px h-full">
+					<el-menu-item index="1">业务表</el-menu-item>
+					<el-menu-item index="2">流程表</el-menu-item>
+					<el-menu-item index="3">外部数据库</el-menu-item>
+				</el-menu>
+			</div>
+			<div class="flex-1 p-12px">
+				<el-form inline>
+					<el-form-item label="表名">
+						<el-input placeholder="请输入表名"></el-input>
+					</el-form-item>
+					<el-form-item label="表描述">
+						<el-input placeholder="请输入表描述"></el-input>
+					</el-form-item>
+				</el-form>
+				<ul>
+					<li
+						v-for="table in tableList"
+						:key="table.name"
+						class="flex items-center justify-between cursor-pointer mb-12px p-12px hover:bg-gray-100"
+					>
+						<div class="left flex items-center gap-24px">
+							<div class="icon w-40px h-40px bg-#ffb800 rounded-md grid place-items-center">
+								<Icon icon="iconoir:database-solid" color="#fff" height="24" width="24" />
+							</div>
+							<div>
+								<div class="text-#333 text-xs">{{ table.name }}</div>
+								<div class="text-#666 text-xs">{{ table.desc }}</div>
+							</div>
+						</div>
+						<el-button type="primary" @click="onAdd(table)">添加</el-button>
+					</li>
+				</ul>
+			</div>
+		</div>
+	</el-dialog>
+</template>
+
+<script setup lang="ts">
+import { Icon } from '@repo/ui'
+import { ref } from 'vue'
+
+const emit = defineEmits<{
+	add: [tableName: unknown]
+}>()
+const visible = ref(false)
+
+defineExpose({
+	open() {
+		visible.value = true
+	}
+})
+
+const tableList = [
+	{
+		name: 'customer_info',
+		desc: '客户信息表',
+		columns: [
+			{
+				name: 'id',
+				type: 'Nvarchar',
+				desc: 'ID'
+			},
+			{
+				name: 'customer_tenant_id',
+				type: 'Nvarchar',
+				desc: '租户ID'
+			},
+			{
+				name: 'customer_address',
+				type: 'Nvarchar',
+				desc: '客户地址'
+			}
+		]
+	},
+	{
+		name: 'device_info',
+		desc: '设备表',
+		columns: [
+			{
+				name: 'id',
+				type: 'Nvarchar',
+				desc: 'ID'
+			},
+			{
+				name: 'time_interval',
+				type: 'Nvarchar',
+				desc: '时间间隔'
+			},
+			{
+				name: 'iotdevice_describe',
+				type: 'Nvarchar',
+				desc: '设备描述'
+			}
+		]
+	}
+]
+
+const onAdd = (table: unknown) => {
+	emit('add', table)
+	visible.value = false
+}
+</script>
+
+<style scoped></style>

+ 5 - 2
packages/ui/components/icon-button/IconButton.vue

@@ -7,7 +7,7 @@
 		:class="{ square }"
 		v-bind="$attrs"
 	>
-		<Icon :icon="icon" :color="iconColor"></Icon>
+		<Icon :icon="icon" :color="iconColor" :width="iconSize" :height="iconSize"></Icon>
 		<slot>{{ label }}</slot>
 	</ElButton>
 </template>
@@ -15,8 +15,9 @@
 <script setup lang="ts">
 import { ElButton } from 'element-plus'
 import Icon from '../icon/Icon.vue'
+import { computed } from 'vue'
 
-withDefaults(
+const props = withDefaults(
 	defineProps<{
 		icon: string
 		iconColor?: string
@@ -33,6 +34,8 @@ withDefaults(
 		loading: false
 	}
 )
+
+const iconSize = computed(() => (props.size === 'large' ? 20 : props.size === 'small' ? 12 : 16))
 </script>
 
 <style lang="less" scoped>