chore(release): v1.1.0 unify DI(strategy), AI equivalence service, config domain refactor, docker alias; health checks and schedules
This commit is contained in:
501
admin-vben/apps/web-antd/src/stores/diy.ts
Normal file
501
admin-vben/apps/web-antd/src/stores/diy.ts
Normal file
@@ -0,0 +1,501 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import { ref, computed } from 'vue';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
import { message, Modal } from 'ant-design-vue';
|
||||
|
||||
import type { GlobalConfig } from '@/views/diy/design/data';
|
||||
|
||||
export interface ComponentItem {
|
||||
id: string;
|
||||
componentName: string;
|
||||
componentTitle: string;
|
||||
title: string;
|
||||
icon?: string;
|
||||
path: string;
|
||||
uses: number;
|
||||
position?: string;
|
||||
ignore?: string[];
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
export const useDiyStore = defineStore('diy', () => {
|
||||
// Basic page info
|
||||
const id = ref(0);
|
||||
const name = ref('');
|
||||
const pageTitle = ref('');
|
||||
const type = ref('');
|
||||
const typeName = ref('');
|
||||
const templateName = ref('');
|
||||
const isDefault = ref(0);
|
||||
const pageMode = ref('diy');
|
||||
|
||||
// Loading state
|
||||
const load = ref(false);
|
||||
|
||||
// Current editing index
|
||||
const currentIndex = ref(-99); // -99 for page settings
|
||||
|
||||
// Edit tab
|
||||
const editTab = ref<'content' | 'style'>('content');
|
||||
|
||||
// Global configuration
|
||||
const global = ref<GlobalConfig>({
|
||||
title: '页面',
|
||||
completeLayout: 'style-1',
|
||||
completeAlign: 'left',
|
||||
borderControl: true,
|
||||
pageStartBgColor: '',
|
||||
pageEndBgColor: '',
|
||||
pageGradientAngle: 'to bottom',
|
||||
bgUrl: '',
|
||||
bgHeightScale: 0,
|
||||
imgWidth: '',
|
||||
imgHeight: '',
|
||||
topStatusBar: {
|
||||
control: true,
|
||||
isShow: true,
|
||||
bgColor: '#ffffff',
|
||||
rollBgColor: '#ffffff',
|
||||
style: 'style-1',
|
||||
styleName: '风格1',
|
||||
textColor: '#333333',
|
||||
rollTextColor: '#333333',
|
||||
textAlign: 'center',
|
||||
inputPlaceholder: '请输入搜索关键词',
|
||||
imgUrl: '',
|
||||
link: { name: '' },
|
||||
},
|
||||
bottomTabBar: {
|
||||
control: true,
|
||||
isShow: true,
|
||||
},
|
||||
popWindow: {
|
||||
imgUrl: '',
|
||||
imgWidth: '',
|
||||
imgHeight: '',
|
||||
count: 'once',
|
||||
show: 0,
|
||||
link: { name: '' },
|
||||
},
|
||||
template: {
|
||||
textColor: '#303133',
|
||||
pageStartBgColor: '',
|
||||
pageEndBgColor: '',
|
||||
pageGradientAngle: 'to bottom',
|
||||
componentBgUrl: '',
|
||||
componentBgAlpha: 2,
|
||||
componentStartBgColor: '',
|
||||
componentEndBgColor: '',
|
||||
componentGradientAngle: 'to bottom',
|
||||
topRounded: 0,
|
||||
bottomRounded: 0,
|
||||
elementBgColor: '',
|
||||
topElementRounded: 0,
|
||||
bottomElementRounded: 0,
|
||||
margin: {
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
both: 0,
|
||||
},
|
||||
isHidden: false,
|
||||
},
|
||||
});
|
||||
|
||||
// Component values
|
||||
const value = ref<any[]>([]);
|
||||
|
||||
// Available components
|
||||
const components = ref<ComponentItem[]>([]);
|
||||
|
||||
// Position types
|
||||
const positionTypes = ['top_fixed', 'right_fixed', 'bottom_fixed', 'left_fixed', 'fixed'];
|
||||
|
||||
// Current component
|
||||
const currentComponent = computed(() => {
|
||||
if (currentIndex.value === -99) {
|
||||
return 'page-settings';
|
||||
}
|
||||
return value.value[currentIndex.value]?.path || '';
|
||||
});
|
||||
|
||||
// Edit component
|
||||
const editComponent = computed(() => {
|
||||
if (currentIndex.value === -99) {
|
||||
return global.value;
|
||||
}
|
||||
return value.value[currentIndex.value];
|
||||
});
|
||||
|
||||
// Initialize store
|
||||
const init = () => {
|
||||
id.value = 0;
|
||||
name.value = '';
|
||||
pageTitle.value = '';
|
||||
type.value = '';
|
||||
typeName.value = '';
|
||||
templateName.value = '';
|
||||
isDefault.value = 0;
|
||||
pageMode.value = 'diy';
|
||||
load.value = false;
|
||||
currentIndex.value = -99;
|
||||
editTab.value = 'content';
|
||||
|
||||
// Reset global config
|
||||
global.value = {
|
||||
title: '页面',
|
||||
completeLayout: 'style-1',
|
||||
completeAlign: 'left',
|
||||
borderControl: true,
|
||||
pageStartBgColor: '',
|
||||
pageEndBgColor: '',
|
||||
pageGradientAngle: 'to bottom',
|
||||
bgUrl: '',
|
||||
bgHeightScale: 100,
|
||||
imgWidth: '',
|
||||
imgHeight: '',
|
||||
topStatusBar: {
|
||||
control: true,
|
||||
isShow: true,
|
||||
bgColor: '#ffffff',
|
||||
rollBgColor: '#ffffff',
|
||||
style: 'style-1',
|
||||
styleName: '风格1',
|
||||
textColor: '#333333',
|
||||
rollTextColor: '#333333',
|
||||
textAlign: 'center',
|
||||
inputPlaceholder: '请输入搜索关键词',
|
||||
imgUrl: '',
|
||||
link: { name: '' },
|
||||
},
|
||||
bottomTabBar: {
|
||||
control: true,
|
||||
isShow: true,
|
||||
},
|
||||
popWindow: {
|
||||
imgUrl: '',
|
||||
imgWidth: '',
|
||||
imgHeight: '',
|
||||
count: 'once',
|
||||
show: 0,
|
||||
link: { name: '' },
|
||||
},
|
||||
template: {
|
||||
textColor: '#303133',
|
||||
pageStartBgColor: '',
|
||||
pageEndBgColor: '',
|
||||
pageGradientAngle: 'to bottom',
|
||||
componentBgUrl: '',
|
||||
componentBgAlpha: 2,
|
||||
componentStartBgColor: '',
|
||||
componentEndBgColor: '',
|
||||
componentGradientAngle: 'to bottom',
|
||||
topRounded: 0,
|
||||
bottomRounded: 0,
|
||||
elementBgColor: '',
|
||||
topElementRounded: 0,
|
||||
bottomElementRounded: 0,
|
||||
margin: {
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
both: 0,
|
||||
},
|
||||
isHidden: false,
|
||||
},
|
||||
};
|
||||
|
||||
value.value = [];
|
||||
components.value = [];
|
||||
};
|
||||
|
||||
// Generate random ID
|
||||
const generateRandom = (len: number = 5) => {
|
||||
return Number(Math.random().toString().substr(3, len) + Date.now()).toString(36);
|
||||
};
|
||||
|
||||
// Add component
|
||||
const addComponent = (key: string, data: any) => {
|
||||
if (!load.value) return;
|
||||
|
||||
let component = cloneDeep(data);
|
||||
component.id = generateRandom();
|
||||
component.componentName = key;
|
||||
component.componentTitle = component.title;
|
||||
component.ignore = component.ignore || [];
|
||||
|
||||
// Apply template properties
|
||||
let template = cloneDeep(global.value.template);
|
||||
Object.assign(component, template);
|
||||
|
||||
if (component.template) {
|
||||
Object.assign(component, component.template);
|
||||
delete component.template;
|
||||
}
|
||||
|
||||
// Check if component can be added
|
||||
if (!checkComponentIsAdd(component)) {
|
||||
message.warning(`${component.componentTitle}最多只能添加${component.uses}个`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle position-based components
|
||||
if (component.position && positionTypes.includes(component.position)) {
|
||||
if (component.position === 'top_fixed') {
|
||||
value.value.splice(0, 0, component);
|
||||
currentIndex.value = 0;
|
||||
} else if (component.position === 'bottom_fixed') {
|
||||
value.value.splice(value.value.length, 0, component);
|
||||
currentIndex.value = value.value.length - 1;
|
||||
} else {
|
||||
value.value.splice(0, 0, component);
|
||||
currentIndex.value = 0;
|
||||
}
|
||||
} else if (currentIndex.value === -99) {
|
||||
// Add to end
|
||||
let index = value.value.length;
|
||||
for (let i = value.value.length - 1; i >= 0; i--) {
|
||||
if (value.value[i].position === 'bottom_fixed') {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (index === value.value.length) {
|
||||
value.value.push(component);
|
||||
currentIndex.value = value.value.length - 1;
|
||||
} else {
|
||||
value.value.splice(index, 0, component);
|
||||
currentIndex.value = index;
|
||||
}
|
||||
} else {
|
||||
// Insert after current
|
||||
let index = currentIndex.value + 1;
|
||||
for (let i = value.value.length - 1; i >= 0; i--) {
|
||||
if (value.value[i].position === 'bottom_fixed') {
|
||||
if (i === currentIndex.value || (i - currentIndex.value) === 1) {
|
||||
index = i;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
value.value.splice(index, 0, component);
|
||||
currentIndex.value = index;
|
||||
}
|
||||
|
||||
currentComponent.value = component.path;
|
||||
};
|
||||
|
||||
// Check if component can be added
|
||||
const checkComponentIsAdd = (component: ComponentItem) => {
|
||||
if (component.uses === 0) return true;
|
||||
|
||||
let count = 0;
|
||||
for (let i in value.value) {
|
||||
if (value.value[i].componentName === component.componentName) count++;
|
||||
}
|
||||
|
||||
return count < component.uses;
|
||||
};
|
||||
|
||||
// Delete component
|
||||
const delComponent = () => {
|
||||
if (currentIndex.value === -99) return;
|
||||
|
||||
Modal.confirm({
|
||||
title: '删除组件',
|
||||
content: '确定要删除该组件吗?',
|
||||
onOk: () => {
|
||||
value.value.splice(currentIndex.value, 1);
|
||||
|
||||
if (value.value.length === 0) {
|
||||
currentIndex.value = -99;
|
||||
} else if (currentIndex.value === value.value.length) {
|
||||
currentIndex.value--;
|
||||
}
|
||||
|
||||
let component = cloneDeep(value.value[currentIndex.value]);
|
||||
changeCurrentIndex(currentIndex.value, component);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
// Move component up
|
||||
const moveUpComponent = () => {
|
||||
if (currentIndex.value <= 0) return;
|
||||
|
||||
const temp = cloneDeep(value.value[currentIndex.value]);
|
||||
let prevIndex = currentIndex.value - 1;
|
||||
const temp2 = cloneDeep(value.value[prevIndex]);
|
||||
|
||||
if (prevIndex < 0 || (temp2.position && positionTypes.includes(temp2.position))) return;
|
||||
|
||||
if (temp.position && positionTypes.includes(temp.position)) {
|
||||
message.warning('该组件不能移动');
|
||||
return;
|
||||
}
|
||||
|
||||
temp.id = generateRandom();
|
||||
temp2.id = generateRandom();
|
||||
|
||||
value.value[currentIndex.value] = temp2;
|
||||
value.value[prevIndex] = temp;
|
||||
|
||||
changeCurrentIndex(prevIndex, temp);
|
||||
};
|
||||
|
||||
// Move component down
|
||||
const moveDownComponent = () => {
|
||||
if (currentIndex.value >= value.value.length - 1) return;
|
||||
|
||||
const nextIndex = currentIndex.value + 1;
|
||||
const temp = cloneDeep(value.value[currentIndex.value]);
|
||||
temp.id = generateRandom();
|
||||
|
||||
const temp2 = cloneDeep(value.value[nextIndex]);
|
||||
temp2.id = generateRandom();
|
||||
|
||||
if (temp2.position && positionTypes.includes(temp2.position)) return;
|
||||
|
||||
if (temp.position && positionTypes.includes(temp.position)) {
|
||||
message.warning('该组件不能移动');
|
||||
return;
|
||||
}
|
||||
|
||||
value.value[currentIndex.value] = temp2;
|
||||
value.value[nextIndex] = temp;
|
||||
|
||||
changeCurrentIndex(nextIndex, temp);
|
||||
};
|
||||
|
||||
// Copy component
|
||||
const copyComponent = () => {
|
||||
if (currentIndex.value < 0) return;
|
||||
|
||||
let component = cloneDeep(value.value[currentIndex.value]);
|
||||
component.id = generateRandom();
|
||||
|
||||
if (!checkComponentIsAdd(component)) {
|
||||
message.warning(`不能复制,${component.componentTitle}最多只能添加${component.uses}个`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (component.position && positionTypes.includes(component.position)) {
|
||||
message.warning(`不能复制,${component.componentTitle}只能添加1个`);
|
||||
return;
|
||||
}
|
||||
|
||||
const index = currentIndex.value + 1;
|
||||
value.value.splice(index, 0, component);
|
||||
changeCurrentIndex(index, component);
|
||||
};
|
||||
|
||||
// Reset component
|
||||
const resetComponent = () => {
|
||||
if (currentIndex.value < 0) return;
|
||||
|
||||
Modal.confirm({
|
||||
title: '重置组件',
|
||||
content: '确定要重置该组件吗?',
|
||||
onOk: () => {
|
||||
for (let i = 0; i < components.value.length; i++) {
|
||||
if (components.value[i].componentName === editComponent.value.componentName) {
|
||||
Object.assign(editComponent.value, components.value[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
// Change current index
|
||||
const changeCurrentIndex = (index: number, component?: any) => {
|
||||
currentIndex.value = index;
|
||||
if (index === -99) {
|
||||
currentComponent.value = 'page-settings';
|
||||
} else if (component) {
|
||||
currentComponent.value = component.path;
|
||||
}
|
||||
};
|
||||
|
||||
// Post message to iframe
|
||||
const postMessage = () => {
|
||||
const diyData = {
|
||||
pageMode: pageMode.value,
|
||||
currentIndex: currentIndex.value,
|
||||
global: global.value,
|
||||
value: value.value,
|
||||
};
|
||||
|
||||
const iframe = document.getElementById('previewIframe') as HTMLIFrameElement;
|
||||
if (iframe && iframe.contentWindow) {
|
||||
iframe.contentWindow.postMessage(JSON.stringify(diyData), '*');
|
||||
}
|
||||
};
|
||||
|
||||
// Validate
|
||||
const verify = () => {
|
||||
if (pageTitle.value === '') {
|
||||
message.warning('请输入页面名称');
|
||||
changeCurrentIndex(-99);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (global.value.popWindow.show && !global.value.popWindow.imgUrl) {
|
||||
message.warning('请上传弹窗图片');
|
||||
return false;
|
||||
}
|
||||
|
||||
for (let i = 0; i < value.value.length; i++) {
|
||||
try {
|
||||
if (value.value[i].verify) {
|
||||
const res = value.value[i].verify(i);
|
||||
if (!res.code) {
|
||||
changeCurrentIndex(i, value.value[i]);
|
||||
message.warning(res.message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('verify Error:', e, i, value.value[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
return {
|
||||
// State
|
||||
id,
|
||||
name,
|
||||
pageTitle,
|
||||
type,
|
||||
typeName,
|
||||
templateName,
|
||||
isDefault,
|
||||
pageMode,
|
||||
load,
|
||||
currentIndex,
|
||||
editTab,
|
||||
global,
|
||||
value,
|
||||
components,
|
||||
|
||||
// Computed
|
||||
currentComponent,
|
||||
editComponent,
|
||||
|
||||
// Actions
|
||||
init,
|
||||
generateRandom,
|
||||
addComponent,
|
||||
checkComponentIsAdd,
|
||||
delComponent,
|
||||
moveUpComponent,
|
||||
moveDownComponent,
|
||||
copyComponent,
|
||||
resetComponent,
|
||||
changeCurrentIndex,
|
||||
postMessage,
|
||||
verify,
|
||||
};
|
||||
});
|
||||
Reference in New Issue
Block a user