浏览代码

生成随机id

kagg886 1 月之前
父节点
当前提交
69c8a3c54b

+ 3 - 2
src/components/assistant/ComponentLibrary.vue

@@ -2,13 +2,14 @@
 import { ref } from 'vue'
 import { Plus, Document } from '@element-plus/icons-vue'
 import Markdown from '/@/components/markdown/Markdown.vue'
+import type { ComponentLibraryItem, Content } from './types'
 
 const emit = defineEmits<{
-	addCard: [cardData: { title: string; data: string }]
+	addCard: [cardData: Content]
 }>()
 
 // 组件库数据
-const componentLibrary = ref([
+const componentLibrary = ref<ComponentLibraryItem[]>([
 	{
 		id: 'quote-block',
 		title: '引用块',

+ 16 - 26
src/components/assistant/DashboardDesigner.vue

@@ -2,49 +2,40 @@
 import { ref, computed, nextTick } from 'vue'
 import DraggableCard from './DraggableCard.vue'
 import { Delete, Document } from '@element-plus/icons-vue'
-
-type MarkdownDashBoard = {
-	x: number
-	y: number
-	w: number
-	h: number
-	z: number
-	title: string
-	data: string
-}
+import type { MarkdownDashBoard, Position, Size, Content, AddCardData } from './types'
 
 const props = defineProps<{
 	cards: MarkdownDashBoard[]
 }>()
 
 const emit = defineEmits<{
-	updatePosition: [index: number, position: { x: number; y: number }]
-	updateSize: [index: number, size: { w: number; h: number }]
-	updateContent: [index: number, content: { title: string; data: string }]
-	removeCard: [index: number]
-	addCard: [cardData: { title: string; data: string; x: number; y: number }]
+	updatePosition: [id: string, position: Position]
+	updateSize: [id: string, size: Size]
+	updateContent: [id: string, content: Content]
+	removeCard: [id: string]
+	addCard: [cardData: AddCardData]
 }>()
 
 const designerContainer = ref<HTMLElement>()
 
 // 处理卡片位置更新
-const handleCardPositionUpdate = (index: number, position: { x: number; y: number }) => {
-	emit('updatePosition', index, position)
+const handleCardPositionUpdate = (id: string, position: Position) => {
+	emit('updatePosition', id, position)
 }
 
 // 处理卡片大小更新
-const handleCardSizeUpdate = (index: number, size: { w: number; h: number }) => {
-	emit('updateSize', index, size)
+const handleCardSizeUpdate = (id: string, size: Size) => {
+	emit('updateSize', id, size)
 }
 
 // 处理卡片内容更新
-const handleCardContentUpdate = (index: number, content: { title: string; data: string }) => {
-	emit('updateContent', index, content)
+const handleCardContentUpdate = (id: string, content: Content) => {
+	emit('updateContent', id, content)
 }
 
 // 处理卡片删除
-const handleCardRemove = (index: number) => {
-	emit('removeCard', index)
+const handleCardRemove = (id: string) => {
+	emit('removeCard', id)
 }
 
 // 处理拖拽放置
@@ -102,10 +93,9 @@ const handleDragOver = (event: DragEvent) => {
 
 			<!-- 渲染所有卡片 -->
 			<DraggableCard
-				v-for="(card, index) in cards"
-				:key="`card-${index}`"
+				v-for="card in cards"
+				:key="card.id"
 				:card="card"
-				:index="index"
 				@update-position="handleCardPositionUpdate"
 				@update-size="handleCardSizeUpdate"
 				@update-content="handleCardContentUpdate"

+ 10 - 20
src/components/assistant/DraggableCard.vue

@@ -2,34 +2,24 @@
 import { ref, computed, onUnmounted } from 'vue'
 import { Delete, MoreFilled, Edit } from '@element-plus/icons-vue'
 import Markdown from '/@/components/markdown/Markdown.vue'
-
-type MarkdownDashBoard = {
-	x: number
-	y: number
-	w: number
-	h: number
-	z: number
-	title: string
-	data: string
-}
+import type { MarkdownDashBoard, Position, Size, Content, ResizeType } from './types'
 
 const props = defineProps<{
 	card: MarkdownDashBoard
-	index: number
 }>()
 
 const emit = defineEmits<{
-	updatePosition: [index: number, position: { x: number; y: number }]
-	updateSize: [index: number, size: { w: number; h: number }]
-	updateContent: [index: number, content: { title: string; data: string }]
-	remove: [index: number]
+	updatePosition: [id: string, position: Position]
+	updateSize: [id: string, size: Size]
+	updateContent: [id: string, content: Content]
+	remove: [id: string]
 }>()
 
 const cardRef = ref<HTMLElement>()
 const isDragging = ref(false)
 const isResizing = ref(false)
 const dragOffset = ref({ x: 0, y: 0 })
-const resizeType = ref<'se' | 'e' | 's' | ''>('')
+const resizeType = ref<ResizeType>('')
 const initialSize = ref({ w: 0, h: 0 })
 const initialPosition = ref({ x: 0, y: 0 })
 
@@ -103,7 +93,7 @@ const handleDrag = (event: MouseEvent) => {
 	const constrainedX = Math.max(0, Math.min(100 - props.card.w, newX))
 	const constrainedY = Math.max(0, Math.min(100 - props.card.h, newY))
 
-	emit('updatePosition', props.index, { x: constrainedX, y: constrainedY })
+	emit('updatePosition', props.card.id, { x: constrainedX, y: constrainedY })
 }
 
 // 处理拖拽调整大小
@@ -130,7 +120,7 @@ const handleResize = (event: MouseEvent) => {
 		newH = Math.max(10, Math.min(100 - props.card.y, initialSize.value.h + deltaYPercent))
 	}
 
-	emit('updateSize', props.index, { w: newW, h: newH })
+	emit('updateSize', props.card.id, { w: newW, h: newH })
 }
 
 // 停止拖拽移动
@@ -158,7 +148,7 @@ const handleEdit = () => {
 // 确认编辑
 const confirmEdit = () => {
 	if (editTitle.value.trim() && editData.value.trim()) {
-		emit('updateContent', props.index, {
+		emit('updateContent', props.card.id, {
 			title: editTitle.value.trim(),
 			data: editData.value.trim()
 		})
@@ -175,7 +165,7 @@ const cancelEdit = () => {
 
 // 删除卡片
 const handleRemove = () => {
-	emit('remove', props.index)
+	emit('remove', props.card.id)
 }
 
 // 清理事件监听器

+ 70 - 0
src/components/assistant/types.ts

@@ -0,0 +1,70 @@
+/**
+ * 仪表板助手相关类型定义
+ */
+
+// 仪表板卡片类型
+export interface MarkdownDashBoard {
+	/** 卡片唯一标识 */
+	id: string
+	/** X坐标 (百分比 0-100) */
+	x: number
+	/** Y坐标 (百分比 0-100) */
+	y: number
+	/** 宽度 (百分比 0-100) */
+	w: number
+	/** 高度 (百分比 0-100) */
+	h: number
+	/** 层级 (z-index) */
+	z: number
+	/** 卡片标题 */
+	title: string
+	/** 卡片内容 (Markdown格式) */
+	data: string
+}
+
+// 位置信息类型
+export interface Position {
+	x: number
+	y: number
+}
+
+// 尺寸信息类型
+export interface Size {
+	w: number
+	h: number
+}
+
+// 内容信息类型
+export interface Content {
+	title: string
+	data: string
+}
+
+// 组件库项目类型
+export interface ComponentLibraryItem {
+	/** 组件唯一标识 */
+	id: string
+	/** 组件标题 */
+	title: string
+	/** 组件图标 */
+	icon: any
+	/** 组件描述 */
+	description: string
+	/** 组件完整数据 */
+	data: string
+	/** 组件预览数据 */
+	preview: string
+}
+
+// 拖拽调整大小类型
+export type ResizeType = 'se' | 'e' | 's' | ''
+
+// 卡片添加数据类型
+export interface AddCardData {
+	title: string
+	data: string
+	x?: number
+	y?: number
+}
+
+

+ 30 - 26
src/views/assistant/dashboard/edit.vue

@@ -4,17 +4,7 @@ import { computed, ref } from 'vue'
 import DashboardDesigner from '/@/components/assistant/DashboardDesigner.vue'
 import ComponentLibrary from '/@/components/assistant/ComponentLibrary.vue'
 import { ElMessage } from 'element-plus'
-
-type MarkdownDashBoard = {
-	x: number
-	y: number
-	w: number
-	h: number
-	z: number
-
-	title: string
-	data: string
-}
+import type { MarkdownDashBoard, Position, Size, Content, AddCardData } from '/@/components/assistant/types'
 
 // 预留props,暂时不使用
 // const props = defineProps<{
@@ -24,6 +14,7 @@ type MarkdownDashBoard = {
 const data = ref<MarkdownDashBoard[]>([
 	// 示例数据
 	{
+		id: 'card-1',
 		x: 10,
 		y: 10,
 		w: 40,
@@ -33,6 +24,7 @@ const data = ref<MarkdownDashBoard[]>([
 		data: '> 这是一个引用块示例\n> \n> 可以包含多行内容'
 	},
 	{
+		id: 'card-2',
 		x: 55,
 		y: 15,
 		w: 35,
@@ -53,6 +45,11 @@ const data = ref<MarkdownDashBoard[]>([
 
 const renderer = computed<MarkdownDashBoard[]>(() => [...data.value].sort((a, b) => a.z - b.z))
 
+// 生成唯一ID
+const generateId = () => {
+	return `card-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`
+}
+
 const { loading: loadingDashboardSubmit, doLoading: doLoadingDashboardSubmit } = useLoading(async () => {
 	try {
 		// TODO: 实际的保存逻辑
@@ -65,8 +62,9 @@ const { loading: loadingDashboardSubmit, doLoading: doLoadingDashboardSubmit } =
 })
 
 // 添加新卡片
-const addCard = (cardData: { title: string; data: string; x?: number; y?: number }) => {
+const addCard = (cardData: AddCardData) => {
 	const newCard: MarkdownDashBoard = {
+		id: generateId(),
 		x: cardData.x ?? Math.random() * 50, // 使用传入位置或随机位置
 		y: cardData.y ?? Math.random() * 50,
 		w: 30,
@@ -79,32 +77,38 @@ const addCard = (cardData: { title: string; data: string; x?: number; y?: number
 }
 
 // 更新卡片位置
-const updateCardPosition = (index: number, position: { x: number; y: number }) => {
-	if (data.value[index]) {
-		data.value[index].x = position.x
-		data.value[index].y = position.y
+const updateCardPosition = (id: string, position: Position) => {
+	const card = data.value.find(item => item.id === id)
+	if (card) {
+		card.x = position.x
+		card.y = position.y
 	}
 }
 
 // 更新卡片大小
-const updateCardSize = (index: number, size: { w: number; h: number }) => {
-	if (data.value[index]) {
-		data.value[index].w = size.w
-		data.value[index].h = size.h
+const updateCardSize = (id: string, size: Size) => {
+	const card = data.value.find(item => item.id === id)
+	if (card) {
+		card.w = size.w
+		card.h = size.h
 	}
 }
 
 // 更新卡片内容
-const updateCardContent = (index: number, content: { title: string; data: string }) => {
-	if (data.value[index]) {
-		data.value[index].title = content.title
-		data.value[index].data = content.data
+const updateCardContent = (id: string, content: Content) => {
+	const card = data.value.find(item => item.id === id)
+	if (card) {
+		card.title = content.title
+		card.data = content.data
 	}
 }
 
 // 删除卡片
-const removeCard = (index: number) => {
-	data.value.splice(index, 1)
+const removeCard = (id: string) => {
+	const index = data.value.findIndex(item => item.id === id)
+	if (index !== -1) {
+		data.value.splice(index, 1)
+	}
 }
 </script>