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:
wanwu
2025-11-14 02:34:06 +08:00
parent e54041331a
commit de821ae5fd
1501 changed files with 60179 additions and 21496 deletions

View 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,
};
});