|
@@ -1,293 +1,240 @@
|
|
|
-import { create } from 'zustand'
|
|
|
-import { saveComponent as _save, saveComponentBatch as _saveBatch, getComponentList, delComponent as _del, sortComponent as _sort } from '@/service/component'
|
|
|
-import { TEntityComponent } from '@/types/index'
|
|
|
+import { create } from "zustand";
|
|
|
+import { editAgentWebsite as _editAgentWebsite, editAgentAvatar, editAgentWebsite } from "@/service/agent";
|
|
|
+import { TComponentItem } from "@/types/agent";
|
|
|
+
|
|
|
+
|
|
|
+function safeSwap(arr:any[], index1:number, index2: number) {
|
|
|
+ if (
|
|
|
+ index1 >= 0 &&
|
|
|
+ index1 < arr.length &&
|
|
|
+ index2 >= 0 &&
|
|
|
+ index2 < arr.length
|
|
|
+ ) {
|
|
|
+ [arr[index1], arr[index2]] = [arr[index2], arr[index1]];
|
|
|
+ }
|
|
|
+ return arr;
|
|
|
+}
|
|
|
|
|
|
export interface ComponentState {
|
|
|
- loading: boolean
|
|
|
- maxIndex: number // 最大组件索引
|
|
|
- insertIndex: number // 插入组件的索引
|
|
|
- components: TEntityComponent[] | [] // 后期是否需要改成链表方便中间插入删除等操作??
|
|
|
- currentComponent: TEntityComponent | null
|
|
|
- fetchComponentList: (profileID: string) => Promise<TEntityComponent[]>
|
|
|
- delComponent: (c: TEntityComponent) => Promise<void>
|
|
|
- saveComponent: (c: TEntityComponent) => Promise<TEntityComponent | null>
|
|
|
- insertComponent: (c: TEntityComponent) => Promise<TEntityComponent | null>
|
|
|
- saveBatch: (c: TEntityComponent[]) => Promise<TEntityComponent[] | null>
|
|
|
- setCurrentComponent: (component: TEntityComponent | null) => TEntityComponent | null
|
|
|
- calcMaxIndex: (components?: TEntityComponent[]) => void
|
|
|
- resortComponent: () => void
|
|
|
- swapTwoComponent: (c: TEntityComponent, direction: number) => Promise<boolean>
|
|
|
- setInsertIndex: (index: number) => void
|
|
|
+ agentId: string,
|
|
|
+ maxIndex: number; // 最大组件索引
|
|
|
+ insertIndex: number; // 插入组件的索引
|
|
|
+ components: TComponentItem[] | []; // 后期是否需要改成链表方便中间插入删除等操作??
|
|
|
+ currentComponent: TComponentItem | null;
|
|
|
+ setComponentList: (list: TComponentItem[], agentId: string) => void;
|
|
|
+ delComponent: (c: TComponentItem) => Promise<void>;
|
|
|
+ saveComponent: (c: TComponentItem) => Promise<TComponentItem | null>;
|
|
|
+ insertComponent: (c: TComponentItem[]) => Promise<TComponentItem[] | null>;
|
|
|
+ swapTwoComponent: (c: TComponentItem, direction: number) => Promise<void>;
|
|
|
+ setCurrentComponent: (
|
|
|
+ component: TComponentItem | null
|
|
|
+ ) => TComponentItem | null;
|
|
|
+ setInsertIndex: (index: number) => void;
|
|
|
}
|
|
|
|
|
|
// 索引位置最大值
|
|
|
-const getMaxIndex = (components: TEntityComponent[]) => {
|
|
|
+const getMaxIndex = (components: TComponentItem[]) => {
|
|
|
return components.reduce((acc, cur) => {
|
|
|
- return Math.max(acc, cur.index ?? 1)
|
|
|
- }, 0)
|
|
|
-}
|
|
|
+ return Math.max(acc, cur.data.index ?? 1);
|
|
|
+ }, 0);
|
|
|
+};
|
|
|
// 根据索引位置 index 值 从小到大 排序
|
|
|
-export const sortComponentsByIndex = (a: TEntityComponent, b: TEntityComponent) => {
|
|
|
- if (a.index === b.index) return 0
|
|
|
- if (a.index === undefined || b.index === undefined) {
|
|
|
- return 0
|
|
|
+export const sortComponentsByIndex = (a: TComponentItem, b: TComponentItem) => {
|
|
|
+ if (a.data.index === b.data.index) return 0;
|
|
|
+ if (a.data.index === undefined || b.data.index === undefined) {
|
|
|
+ return 0;
|
|
|
}
|
|
|
- return a.index - b.index
|
|
|
-}
|
|
|
+ return a.data.index - b.data.index;
|
|
|
+};
|
|
|
|
|
|
export const useComponentStore = create<ComponentState>((set, get) => ({
|
|
|
loading: false,
|
|
|
+ agentId: '',
|
|
|
components: [],
|
|
|
currentComponent: null,
|
|
|
maxIndex: 1,
|
|
|
insertIndex: -1,
|
|
|
- fetchComponentList: async (profileId: string) => {
|
|
|
- const response = await getComponentList(profileId)
|
|
|
- // 兼容旧数据 images 转 media
|
|
|
- if (response.code === 0 && response.data) {
|
|
|
- response.data.map( item => {
|
|
|
- if(item.type === 'images' && item.data?.images?.length){
|
|
|
- item.data.media = item.data.images.map((img:any)=> {
|
|
|
- return {
|
|
|
- url: img.src,
|
|
|
- fileType: 'image',
|
|
|
- }
|
|
|
- })
|
|
|
- }
|
|
|
- return item
|
|
|
- })
|
|
|
- let sorted = response.data.sort(sortComponentsByIndex)
|
|
|
- set({ components: sorted, maxIndex: getMaxIndex(sorted) })
|
|
|
- }
|
|
|
- return response?.data
|
|
|
+ setComponentList: (list: TComponentItem[], agentId: string) => {
|
|
|
+ let sorted = list.sort(sortComponentsByIndex);
|
|
|
+ set({agentId, components: sorted, maxIndex: getMaxIndex(sorted) });
|
|
|
},
|
|
|
- insertComponent: async (c: TEntityComponent) => {
|
|
|
- const insertIndex = get().insertIndex
|
|
|
- let _components = get().components.sort(sortComponentsByIndex)
|
|
|
- set({loading: false})
|
|
|
- if (insertIndex === -1) {
|
|
|
- return null
|
|
|
- }
|
|
|
- console.log('insertIndex:', insertIndex)
|
|
|
- if (insertIndex === 0) {
|
|
|
- // 顶部插入
|
|
|
- c.index = 1;
|
|
|
- }else if(insertIndex === _components.length){
|
|
|
- // 底部插入
|
|
|
- c.index = insertIndex + 1
|
|
|
- }else{
|
|
|
- // 中间插入
|
|
|
- c.index = insertIndex + 1
|
|
|
- }
|
|
|
- console.log('插入位置', c.index)
|
|
|
-
|
|
|
- // 先保存生成 id
|
|
|
- const res = await _save(c)
|
|
|
- const saved = res?.data
|
|
|
- if (!saved) {
|
|
|
- set({loading: false})
|
|
|
- return null
|
|
|
- }
|
|
|
-
|
|
|
- // 如果插入的是最后一个位置则其余无需变动
|
|
|
- if (insertIndex === _components.length) {
|
|
|
- set({
|
|
|
- components: [..._components, saved],
|
|
|
- loading: false
|
|
|
- })
|
|
|
- return saved
|
|
|
- }
|
|
|
+ insertComponent: async (list: TComponentItem[]) => {
|
|
|
|
|
|
- // 在最顶上插入
|
|
|
- if (insertIndex === 0) {
|
|
|
- // 其余组件索引+1
|
|
|
- _components = _components.map((item: TEntityComponent) => {
|
|
|
- if (item.index !== undefined) {
|
|
|
- item.index = item.index + 1
|
|
|
- }
|
|
|
- return item
|
|
|
+
|
|
|
+ const insertIndex = get().insertIndex;
|
|
|
+ let _components = get().components.sort(sortComponentsByIndex);
|
|
|
+ console.log('current components list:', _components)
|
|
|
+ const _componentsLen = _components.length
|
|
|
+
|
|
|
+
|
|
|
+ console.log("insertIndex:", insertIndex);
|
|
|
+ if (insertIndex === -1) {
|
|
|
+ console.log('顶部插入')
|
|
|
+ // 顶部插入, 原组件列表所有 index + list.length
|
|
|
+ _components = _components.map((item: TComponentItem) => {
|
|
|
+ item.data.index = item.data.index + list.length;
|
|
|
+ return item;
|
|
|
+ });
|
|
|
+ _components = [...list, ..._components];
|
|
|
+ } else if (insertIndex === _componentsLen - 1) {
|
|
|
+ console.log('底部插入')
|
|
|
+ // 底部插入, 所有新插入的组件 index 需要加上已存在组件列表长度
|
|
|
+ list = list.map( c => {
|
|
|
+ c.data.index = c.data.index + _componentsLen
|
|
|
+ return c
|
|
|
})
|
|
|
- _components = [saved, ..._components]
|
|
|
+ _components = [..._components, ...list];
|
|
|
} else {
|
|
|
- // 中间位置插入
|
|
|
- // 插入位置之后的组件索引+1
|
|
|
- const restIndex = insertIndex
|
|
|
+ // 中间插入,
|
|
|
+ console.log('中间插入')
|
|
|
+ const restIndex = insertIndex + 1;
|
|
|
+ list = list.map( c => {
|
|
|
+ c.data.index = c.data.index + restIndex
|
|
|
+ return c
|
|
|
+ })
|
|
|
+
|
|
|
let rest = _components.slice(restIndex).map((item) => {
|
|
|
- if (item.index) {
|
|
|
- item.index = item.index + 1
|
|
|
+ if (item.data.index) {
|
|
|
+ item.data.index = item.data.index + list.length;
|
|
|
}
|
|
|
- console.log(item.index, item.data)
|
|
|
- return item
|
|
|
- })
|
|
|
-
|
|
|
- _components = [..._components.slice(0, restIndex), saved, ...rest]
|
|
|
+ console.log(item.data.index, item.data);
|
|
|
+ return item;
|
|
|
+ });
|
|
|
+
|
|
|
+ _components = [..._components.slice(0, restIndex), ...list, ...rest];
|
|
|
+ console.log(_components,111)
|
|
|
}
|
|
|
+
|
|
|
+
|
|
|
+ set({components: _components})
|
|
|
|
|
|
- // 顶上和中间位置插入需要调整整个组件列表
|
|
|
- await get().saveBatch(_components)
|
|
|
- return saved
|
|
|
+ return _components;
|
|
|
},
|
|
|
- saveComponent: async (c: TEntityComponent) => {
|
|
|
- console.log('saveComponent')
|
|
|
-
|
|
|
+ saveComponent: async (c: TComponentItem) => {
|
|
|
+ console.log("saveComponent");
|
|
|
+
|
|
|
// insertIndex 是组件列表插入组件时提前设置的
|
|
|
const insertIndex = get().insertIndex;
|
|
|
- console.log(c.id, insertIndex)
|
|
|
+ console.log(c.id, insertIndex);
|
|
|
// 没有 id 且 insertIndex > -1 说明是插入组件
|
|
|
- if (c.id === undefined && insertIndex > -1) {
|
|
|
- console.log('insertComponentBatch:', c, insertIndex)
|
|
|
-
|
|
|
- return await get().insertComponent(c)
|
|
|
+ if (c.id === undefined && insertIndex > -1) {
|
|
|
+ console.log("insertComponentBatch:", c, insertIndex);
|
|
|
+
|
|
|
+ return await get().insertComponent(c);
|
|
|
}
|
|
|
|
|
|
// 简单更新组件
|
|
|
- console.log('updateComponent: ', c, insertIndex)
|
|
|
+ console.log("updateComponent: ", c, insertIndex);
|
|
|
// 如果是普通保存(直接 tabbar 点击添加组件按钮进入,非插入)
|
|
|
- if(c.id === undefined){
|
|
|
-
|
|
|
- return null
|
|
|
+ if (c.id === undefined) {
|
|
|
+ return null;
|
|
|
}
|
|
|
// 普通更新或新建
|
|
|
- const res = await _save(c)
|
|
|
+ const res = await _save(c);
|
|
|
if (res.code !== 0) {
|
|
|
-
|
|
|
- return null
|
|
|
+ return null;
|
|
|
}
|
|
|
set((state) => {
|
|
|
- let _components = state.components
|
|
|
+ let _components = state.components;
|
|
|
if (c.id) {
|
|
|
- _components = _components.filter((item: TEntityComponent) => item?.id !== c.id)
|
|
|
+ _components = _components.filter(
|
|
|
+ (item: TComponentItem) => item?.id !== c.id
|
|
|
+ );
|
|
|
}
|
|
|
- let sorted = [..._components, res.data].sort(sortComponentsByIndex)
|
|
|
- state.calcMaxIndex(sorted)
|
|
|
+ let sorted = [..._components, res.data].sort(sortComponentsByIndex);
|
|
|
+ state.calcMaxIndex(sorted);
|
|
|
return {
|
|
|
components: sorted,
|
|
|
- loading: false
|
|
|
- }
|
|
|
- })
|
|
|
-
|
|
|
- return res?.data
|
|
|
+ loading: false,
|
|
|
+ };
|
|
|
+ });
|
|
|
+
|
|
|
+ return res?.data;
|
|
|
},
|
|
|
- // 批量保存
|
|
|
- saveBatch: async (batchComponent: TEntityComponent[]) => {
|
|
|
-
|
|
|
- if(!batchComponent.length){
|
|
|
- return null
|
|
|
- }
|
|
|
- const res = await _saveBatch(batchComponent)
|
|
|
- if (res.code !== 0) {
|
|
|
-
|
|
|
- return null
|
|
|
- }
|
|
|
-
|
|
|
- let sorted = (res.data ?? []).sort(sortComponentsByIndex)
|
|
|
- set((state) => {
|
|
|
- state.calcMaxIndex(sorted)
|
|
|
- return {
|
|
|
- components: sorted,
|
|
|
- loading: false
|
|
|
- }
|
|
|
- })
|
|
|
- return res?.data
|
|
|
+ setInsertIndex: (index) => {
|
|
|
+ console.log(index,' setInsertIndex')
|
|
|
+ set({ insertIndex: index });
|
|
|
},
|
|
|
- setCurrentComponent: (component: TEntityComponent | null) => {
|
|
|
- set({ currentComponent: component })
|
|
|
+ setCurrentComponent: (component: TComponentItem | null) => {
|
|
|
+ set({ currentComponent: component });
|
|
|
|
|
|
return component;
|
|
|
},
|
|
|
delComponent: async (c) => {
|
|
|
- if(!c.id){
|
|
|
- return
|
|
|
- }
|
|
|
- const res = await _del(c.id)
|
|
|
- if (res.code === 0) {
|
|
|
- set((state) => {
|
|
|
- const filtered = state.components.filter((item: TEntityComponent) => item?.id !== c.id)
|
|
|
- .sort(sortComponentsByIndex).map((item: TEntityComponent, index)=> {
|
|
|
- return {
|
|
|
- ...item,
|
|
|
- index: index + 1
|
|
|
- }
|
|
|
- })
|
|
|
- get().saveBatch(filtered)
|
|
|
-
|
|
|
- return {
|
|
|
- components: [...filtered]
|
|
|
- }
|
|
|
- })
|
|
|
- }
|
|
|
- },
|
|
|
- setLoading: (loading: boolean) => {
|
|
|
- set({ loading })
|
|
|
+ set({components: []})
|
|
|
+
|
|
|
+ // if (!c.data.id) {
|
|
|
+ // return;
|
|
|
+ // }
|
|
|
+ // set((state) => {
|
|
|
+ // const filtered = state.components
|
|
|
+ // .filter((item: TComponentItem) => item?.data.id !== c.data.id)
|
|
|
+ // .sort(sortComponentsByIndex)
|
|
|
+ // .map((item: TComponentItem, index) => {
|
|
|
+ // return {
|
|
|
+ // ...item,
|
|
|
+ // index: index + 1,
|
|
|
+ // };
|
|
|
+ // });
|
|
|
+ // return {
|
|
|
+ // components: [...filtered],
|
|
|
+ // };
|
|
|
+ // });
|
|
|
},
|
|
|
- calcMaxIndex: (components?: TEntityComponent[]) => {
|
|
|
+
|
|
|
+ calcMaxIndex: (components?: TComponentItem[]) => {
|
|
|
set((state) => {
|
|
|
- return { maxIndex: getMaxIndex(components?? state.components) }
|
|
|
- })
|
|
|
+ return { maxIndex: getMaxIndex(components ?? state.components) };
|
|
|
+ });
|
|
|
},
|
|
|
resortComponent: () => {
|
|
|
-
|
|
|
set((state) => {
|
|
|
- let _comp = state.components
|
|
|
+ let _comp = state.components;
|
|
|
|
|
|
- let r = [..._comp].sort(sortComponentsByIndex)
|
|
|
- console.log(r)
|
|
|
+ let r = [..._comp].sort(sortComponentsByIndex);
|
|
|
+ console.log(r);
|
|
|
return {
|
|
|
components: r,
|
|
|
- loading: false
|
|
|
- }
|
|
|
- })
|
|
|
+ loading: false,
|
|
|
+ };
|
|
|
+ });
|
|
|
},
|
|
|
// 交换两个组件上下位置
|
|
|
- swapTwoComponent: async (c: TEntityComponent, direction: number) => {
|
|
|
-
|
|
|
- const cur = { ...c }
|
|
|
- const components = get().components
|
|
|
- const arrIndex = components.findIndex((item) => item.id === c.id)
|
|
|
- let destComponent: TEntityComponent | null = null;
|
|
|
+ swapTwoComponent: async (c: TComponentItem, direction: number) => {
|
|
|
+ const cur = { ...c };
|
|
|
+ const components = get().components;
|
|
|
+ const arrIndex = components.findIndex((item) => item.data.id === c.data.id);
|
|
|
+ let destComponent: TComponentItem | null = null;
|
|
|
if (direction === 0) {
|
|
|
- destComponent = components[arrIndex - 1]
|
|
|
-
|
|
|
+ destComponent = components[arrIndex - 1];
|
|
|
} else if (direction === 1) {
|
|
|
- destComponent = components[arrIndex + 1]
|
|
|
+ destComponent = components[arrIndex + 1];
|
|
|
}
|
|
|
+
|
|
|
+
|
|
|
+ const tmpList = [...components]
|
|
|
+
|
|
|
+
|
|
|
if (destComponent) {
|
|
|
- destComponent = { ...destComponent }
|
|
|
- const i = cur.index
|
|
|
- cur.index = destComponent.index
|
|
|
- destComponent.index = i;
|
|
|
- const res = await _sort([cur, destComponent])
|
|
|
- if (res.code === 0 && res.data) {
|
|
|
- let temp = [...components]
|
|
|
- res.data.forEach(element => {
|
|
|
- temp = temp.map(item => {
|
|
|
- if (item.id === element.id) {
|
|
|
- return element
|
|
|
- }
|
|
|
- return item
|
|
|
- })
|
|
|
- });
|
|
|
- set({ components: temp, loading: false })
|
|
|
- return true;
|
|
|
- }
|
|
|
- return false
|
|
|
+ destComponent = { ...destComponent };
|
|
|
+ const destComponentIndex = components.findIndex((item) => item.data.id === destComponent?.data.id);
|
|
|
+ const i = cur.data.index;
|
|
|
+ cur.data.index = destComponent.data.index;
|
|
|
+ destComponent.data.index = i;
|
|
|
+ const r = safeSwap(tmpList, arrIndex, destComponentIndex) as TComponentItem[]
|
|
|
+ await editAgentWebsite(get().agentId, {components: r})
|
|
|
+ set({components: r})
|
|
|
}
|
|
|
-
|
|
|
- return false
|
|
|
},
|
|
|
- setInsertIndex(index: number) {
|
|
|
- set({ insertIndex: index })
|
|
|
- },
|
|
|
-}))
|
|
|
+}));
|
|
|
|
|
|
// 获取组件列表中某个组件
|
|
|
export const getComponentById = (id: number) => {
|
|
|
return useComponentStore((state) => {
|
|
|
- return state.components.find(c => c.id === id)
|
|
|
- })
|
|
|
-}
|
|
|
+ return state.components.find((c) => c.id === id);
|
|
|
+ });
|
|
|
+};
|
|
|
// 当前 component 便捷hook
|
|
|
-export const useCurrentComponent = ()=> {
|
|
|
- return useComponentStore((state)=> state.currentComponent)
|
|
|
-}
|
|
|
-
|
|
|
+export const useCurrentComponent = () => {
|
|
|
+ return useComponentStore((state) => state.currentComponent);
|
|
|
+};
|