V 3.3.5
1. 支持自定义MJ API,接口格式必须满足 Midjourney-proxy-plus 接口,https://apiai.apifox.cn/folder-31977042 2. 支持自定义生图包。生图包的格式必须满足 Midjourney-proxy-plus 接口,https://apiai.apifox.cn/folder-31977042 3. 修改软件机器码生成方式 4. 新增推理模式(聚合推文,配合人物提取可以做到人物统一) 5. 修改软件内置人物提取提示词
This commit is contained in:
Vendored
+75
@@ -0,0 +1,75 @@
|
||||
/* eslint-disable */
|
||||
/* prettier-ignore */
|
||||
// @ts-nocheck
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
// Generated by unplugin-auto-import
|
||||
// biome-ignore lint: disable
|
||||
export {}
|
||||
declare global {
|
||||
const EffectScope: typeof import('vue')['EffectScope']
|
||||
const computed: typeof import('vue')['computed']
|
||||
const createApp: typeof import('vue')['createApp']
|
||||
const customRef: typeof import('vue')['customRef']
|
||||
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
|
||||
const defineComponent: typeof import('vue')['defineComponent']
|
||||
const effectScope: typeof import('vue')['effectScope']
|
||||
const getCurrentInstance: typeof import('vue')['getCurrentInstance']
|
||||
const getCurrentScope: typeof import('vue')['getCurrentScope']
|
||||
const h: typeof import('vue')['h']
|
||||
const inject: typeof import('vue')['inject']
|
||||
const isProxy: typeof import('vue')['isProxy']
|
||||
const isReactive: typeof import('vue')['isReactive']
|
||||
const isReadonly: typeof import('vue')['isReadonly']
|
||||
const isRef: typeof import('vue')['isRef']
|
||||
const markRaw: typeof import('vue')['markRaw']
|
||||
const nextTick: typeof import('vue')['nextTick']
|
||||
const onActivated: typeof import('vue')['onActivated']
|
||||
const onBeforeMount: typeof import('vue')['onBeforeMount']
|
||||
const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']
|
||||
const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
|
||||
const onDeactivated: typeof import('vue')['onDeactivated']
|
||||
const onErrorCaptured: typeof import('vue')['onErrorCaptured']
|
||||
const onMounted: typeof import('vue')['onMounted']
|
||||
const onRenderTracked: typeof import('vue')['onRenderTracked']
|
||||
const onRenderTriggered: typeof import('vue')['onRenderTriggered']
|
||||
const onScopeDispose: typeof import('vue')['onScopeDispose']
|
||||
const onServerPrefetch: typeof import('vue')['onServerPrefetch']
|
||||
const onUnmounted: typeof import('vue')['onUnmounted']
|
||||
const onUpdated: typeof import('vue')['onUpdated']
|
||||
const onWatcherCleanup: typeof import('vue')['onWatcherCleanup']
|
||||
const provide: typeof import('vue')['provide']
|
||||
const reactive: typeof import('vue')['reactive']
|
||||
const readonly: typeof import('vue')['readonly']
|
||||
const ref: typeof import('vue')['ref']
|
||||
const resolveComponent: typeof import('vue')['resolveComponent']
|
||||
const shallowReactive: typeof import('vue')['shallowReactive']
|
||||
const shallowReadonly: typeof import('vue')['shallowReadonly']
|
||||
const shallowRef: typeof import('vue')['shallowRef']
|
||||
const toRaw: typeof import('vue')['toRaw']
|
||||
const toRef: typeof import('vue')['toRef']
|
||||
const toRefs: typeof import('vue')['toRefs']
|
||||
const toValue: typeof import('vue')['toValue']
|
||||
const triggerRef: typeof import('vue')['triggerRef']
|
||||
const unref: typeof import('vue')['unref']
|
||||
const useAttrs: typeof import('vue')['useAttrs']
|
||||
const useCssModule: typeof import('vue')['useCssModule']
|
||||
const useCssVars: typeof import('vue')['useCssVars']
|
||||
const useDialog: typeof import('naive-ui')['useDialog']
|
||||
const useId: typeof import('vue')['useId']
|
||||
const useLoadingBar: typeof import('naive-ui')['useLoadingBar']
|
||||
const useMessage: typeof import('naive-ui')['useMessage']
|
||||
const useModel: typeof import('vue')['useModel']
|
||||
const useNotification: typeof import('naive-ui')['useNotification']
|
||||
const useSlots: typeof import('vue')['useSlots']
|
||||
const useTemplateRef: typeof import('vue')['useTemplateRef']
|
||||
const watch: typeof import('vue')['watch']
|
||||
const watchEffect: typeof import('vue')['watchEffect']
|
||||
const watchPostEffect: typeof import('vue')['watchPostEffect']
|
||||
const watchSyncEffect: typeof import('vue')['watchSyncEffect']
|
||||
}
|
||||
// for type re-export
|
||||
declare global {
|
||||
// @ts-ignore
|
||||
export type { Component, Slot, Slots, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue'
|
||||
import('vue')
|
||||
}
|
||||
Vendored
+58
@@ -0,0 +1,58 @@
|
||||
/* eslint-disable */
|
||||
// @ts-nocheck
|
||||
// Generated by unplugin-vue-components
|
||||
// Read more: https://github.com/vuejs/core/pull/3399
|
||||
// biome-ignore lint: disable
|
||||
export {}
|
||||
|
||||
/* prettier-ignore */
|
||||
declare module 'vue' {
|
||||
export interface GlobalComponents {
|
||||
NButton: typeof import('naive-ui')['NButton']
|
||||
NCard: typeof import('naive-ui')['NCard']
|
||||
NCheckbox: typeof import('naive-ui')['NCheckbox']
|
||||
NCode: typeof import('naive-ui')['NCode']
|
||||
NColorPicker: typeof import('naive-ui')['NColorPicker']
|
||||
NConfigProvider: typeof import('naive-ui')['NConfigProvider']
|
||||
NDataTable: typeof import('naive-ui')['NDataTable']
|
||||
NDialogProvider: typeof import('naive-ui')['NDialogProvider']
|
||||
NDivider: typeof import('naive-ui')['NDivider']
|
||||
NDropdown: typeof import('naive-ui')['NDropdown']
|
||||
NDynamicInput: typeof import('naive-ui')['NDynamicInput']
|
||||
NDynamicTags: typeof import('naive-ui')['NDynamicTags']
|
||||
NEmpty: typeof import('naive-ui')['NEmpty']
|
||||
NForm: typeof import('naive-ui')['NForm']
|
||||
NFormItem: typeof import('naive-ui')['NFormItem']
|
||||
NIcon: typeof import('naive-ui')['NIcon']
|
||||
NImage: typeof import('naive-ui')['NImage']
|
||||
NImageGroup: typeof import('naive-ui')['NImageGroup']
|
||||
NInput: typeof import('naive-ui')['NInput']
|
||||
NInputNumber: typeof import('naive-ui')['NInputNumber']
|
||||
NLayout: typeof import('naive-ui')['NLayout']
|
||||
NLayoutSider: typeof import('naive-ui')['NLayoutSider']
|
||||
NLog: typeof import('naive-ui')['NLog']
|
||||
NMenu: typeof import('naive-ui')['NMenu']
|
||||
NMessageProvider: typeof import('naive-ui')['NMessageProvider']
|
||||
NModal: typeof import('naive-ui')['NModal']
|
||||
NModalProvider: typeof import('naive-ui')['NModalProvider']
|
||||
NNotificationProvider: typeof import('naive-ui')['NNotificationProvider']
|
||||
NPopover: typeof import('naive-ui')['NPopover']
|
||||
NProgress: typeof import('naive-ui')['NProgress']
|
||||
NSelect: typeof import('naive-ui')['NSelect']
|
||||
NSlider: typeof import('naive-ui')['NSlider']
|
||||
NSpace: typeof import('naive-ui')['NSpace']
|
||||
NSpin: typeof import('naive-ui')['NSpin']
|
||||
NSplit: typeof import('naive-ui')['NSplit']
|
||||
NSwitch: typeof import('naive-ui')['NSwitch']
|
||||
NTabPane: typeof import('naive-ui')['NTabPane']
|
||||
NTabs: typeof import('naive-ui')['NTabs']
|
||||
NTag: typeof import('naive-ui')['NTag']
|
||||
NText: typeof import('naive-ui')['NText']
|
||||
NTooltip: typeof import('naive-ui')['NTooltip']
|
||||
NTree: typeof import('naive-ui')['NTree']
|
||||
NUpload: typeof import('naive-ui')['NUpload']
|
||||
NUploadDragger: typeof import('naive-ui')['NUploadDragger']
|
||||
RouterLink: typeof import('vue-router')['RouterLink']
|
||||
RouterView: typeof import('vue-router')['RouterView']
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
interface ValidationErrorItem {
|
||||
message?: string;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
interface ValidationErrors {
|
||||
[key: string]: ValidationErrorItem[] | any;
|
||||
message?: string;
|
||||
}
|
||||
|
||||
export function ValidateErrorString(errors: ValidationErrors): string {
|
||||
const errorMessages = Object.values(errors)
|
||||
.map((err) => {
|
||||
return err[0]?.message || '验证错误'
|
||||
})
|
||||
.join(', ')
|
||||
let res = '请修正以下错误: ' + (errorMessages || errors.message);
|
||||
return res
|
||||
}
|
||||
@@ -137,7 +137,7 @@ import { isEmpty } from 'lodash'
|
||||
import VideoCanvas from '../../VideoSubtitle/VideoCanvas.vue'
|
||||
import { SubtitleSavePositionType } from '../../../../../define/enum/waterMarkAndSubtitle.ts'
|
||||
import { DEFINE_STRING } from '../../../../../define/define_string/index.ts'
|
||||
import Setting from './Setting.vue'
|
||||
import Setting from './SettingTabs.vue'
|
||||
import {
|
||||
BookBackTaskType,
|
||||
BookImageCategory,
|
||||
|
||||
@@ -1,32 +1,44 @@
|
||||
<!-- filepath: src\renderer\src\components\Common\NotesCollapse.vue -->
|
||||
<template>
|
||||
<n-collapse class="custom-collapse">
|
||||
<n-collapse class="custom-collapse" :default-expanded-names="defaultExpanded ? [name] : []">
|
||||
<n-collapse-item :name="name" :title="title">
|
||||
<template #header>
|
||||
<div class="collapse-header">
|
||||
<n-icon size="20" class="warning-icon">
|
||||
<svg v-if="iconType === 'warning'" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<svg
|
||||
v-if="iconType === 'warning'"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path fill="currentColor" d="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z" />
|
||||
</svg>
|
||||
<svg v-else-if="iconType === 'info'" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<path fill="currentColor" d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z" />
|
||||
<svg
|
||||
v-else-if="iconType === 'info'"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"
|
||||
/>
|
||||
</svg>
|
||||
<slot v-else name="icon"></slot>
|
||||
</n-icon>
|
||||
<span style="font-size: 16px">{{ title }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
<div class="notes-content">
|
||||
<!-- 如果传入内容数组,自动生成段落 -->
|
||||
<template v-if="items && items.length">
|
||||
<p v-for="(item, index) in items" :key="index" v-html="item"></p>
|
||||
</template>
|
||||
|
||||
|
||||
<!-- 默认插槽用于完全自定义内容 -->
|
||||
<slot></slot>
|
||||
</div>
|
||||
</n-collapse-item>
|
||||
|
||||
</n-collapse>
|
||||
</template>
|
||||
|
||||
@@ -53,6 +65,11 @@ defineProps({
|
||||
items: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
// 是否默认展开
|
||||
defaultExpanded: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
})
|
||||
</script>
|
||||
@@ -146,6 +163,7 @@ defineProps({
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
transition: color 0.2s ease;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.clickable-link:hover {
|
||||
|
||||
@@ -18,20 +18,45 @@
|
||||
</template>
|
||||
<span>VX:xiangbie88</span>
|
||||
</n-popover>
|
||||
<n-button
|
||||
text
|
||||
:style="{
|
||||
width: '24px',
|
||||
fontSize: '24px',
|
||||
color: '#2080f0',
|
||||
display: 'flex',
|
||||
marginLeft: '10px'
|
||||
}"
|
||||
@click="copyMachineId"
|
||||
title="复制机器码"
|
||||
>
|
||||
<n-icon>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="1em" height="1em">
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z"
|
||||
/>
|
||||
</svg>
|
||||
</n-icon>
|
||||
</n-button>
|
||||
</div>
|
||||
<div style="margin: 10px">
|
||||
<div :style="{ margin: '10px' }">
|
||||
<strong>怎么激活? --> </strong>
|
||||
<strong
|
||||
style="color: #e18a3b; margin-left: 10px"
|
||||
:style="{ color: '#e18a3b', marginLeft: '10px' }"
|
||||
@click="OpenTeach('activate')"
|
||||
class="url_class"
|
||||
>软件激活教程 -->
|
||||
</strong>
|
||||
<strong style="margin-left: 10px; color: #ea5514" @click="OpenTeach('lms')" class="url_class">
|
||||
<strong
|
||||
:style="{ marginLeft: '10px', color: '#ea5514' }"
|
||||
@click="OpenTeach('lms')"
|
||||
class="url_class"
|
||||
>
|
||||
后台入口
|
||||
</strong>
|
||||
</div>
|
||||
<div style="margin: 10px; color: red">
|
||||
<div :style="{ margin: '10px', color: 'red' }">
|
||||
有使用问题或者购买问题请联系客服微信
|
||||
<n-popover trigger="hover" raw :show-arrow="false">
|
||||
<template #trigger>
|
||||
@@ -44,13 +69,13 @@
|
||||
/>
|
||||
</n-popover>
|
||||
</div>
|
||||
<div style="margin: 10px; font-size: large; color: red">
|
||||
<div :style="{ margin: '10px', fontSize: 'large', color: 'red' }">
|
||||
教程视频:<span class="url_class" @click="OpenTeach('video')">向北-LAITool</span>
|
||||
</div>
|
||||
<div style="margin: 10px">
|
||||
<div :style="{ margin: '10px' }">
|
||||
详细的教程文档:<span class="url_class" @click="OpenTeach('doc')">教程文档</span>
|
||||
</div>
|
||||
<div style="margin: 10px">
|
||||
<div :style="{ margin: '10px' }">
|
||||
问题/需求收集表:<span class="url_class" @click="OpenQueDoc">问题/需求收集表</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -96,6 +121,39 @@ function OpenQueDoc() {
|
||||
'https://pvwu1oahp5m.feishu.cn/sheets/G5s3sX0KahH1XQtWDazcF70anUb?from=from_copylink'
|
||||
)
|
||||
}
|
||||
|
||||
function copyMachineId() {
|
||||
if (systemStore.machineId) {
|
||||
try {
|
||||
// Try to use browser's Clipboard API (renderer process method)
|
||||
if (navigator.clipboard && navigator.clipboard.writeText) {
|
||||
navigator.clipboard
|
||||
.writeText(systemStore.machineId)
|
||||
.then(() => {
|
||||
message.success('复制成功')
|
||||
})
|
||||
.catch(() => {
|
||||
message.success('复制失败。请手动复制')
|
||||
})
|
||||
} else {
|
||||
// Fallback for browsers without Clipboard API
|
||||
const textarea = document.createElement('textarea')
|
||||
textarea.value = systemStore.machineId
|
||||
textarea.style.position = 'absolute'
|
||||
textarea.style.left = '-9999px'
|
||||
document.body.appendChild(textarea)
|
||||
textarea.select()
|
||||
document.execCommand('copy')
|
||||
document.body.removeChild(textarea)
|
||||
message.success('复制成功')
|
||||
}
|
||||
} catch (error) {
|
||||
message.success('复制失败。请手动复制')
|
||||
}
|
||||
} else {
|
||||
message.error('获取机器码失败')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
</n-layout-content>
|
||||
</n-layout>
|
||||
</n-space>
|
||||
<template #description> 你不知道你有多幸运 </template>
|
||||
<template #description> 正在加载软件授权信息。。。 </template>
|
||||
</n-spin>
|
||||
</template>
|
||||
|
||||
@@ -624,10 +624,6 @@ const menuOptions = computed(() => {
|
||||
}
|
||||
})
|
||||
|
||||
function renderIcon(icon) {
|
||||
return () => h(NIcon, null, { default: () => h(icon) })
|
||||
}
|
||||
|
||||
function OpneBackTask() {
|
||||
let dialogWidth = window.innerWidth * 0.9
|
||||
if (dialogWidth < 800) dialogWidth = 800
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
placeholder="请选择"
|
||||
:options="gpt_auto_inference_options"
|
||||
v-model:value="gpt_auto_inference"
|
||||
style="width: 180px"
|
||||
style="width: 230px"
|
||||
>
|
||||
</n-select>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,273 @@
|
||||
<template>
|
||||
<div class="custom-mj-api-setting">
|
||||
<n-space vertical size="large">
|
||||
<n-select
|
||||
v-model:value="selectedConfig"
|
||||
placeholder="选择要编辑的配置"
|
||||
:options="configOptions"
|
||||
@update:value="handleConfigChange"
|
||||
/>
|
||||
|
||||
<n-form
|
||||
ref="formRef"
|
||||
:model="formData"
|
||||
:rules="rules"
|
||||
label-placement="left"
|
||||
label-width="120px"
|
||||
require-mark-placement="right-hanging"
|
||||
>
|
||||
<n-form-item label="设置名称" path="name">
|
||||
<n-input v-model:value="formData.name" placeholder="请输入设置名称" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="基础URL" path="baseUrl">
|
||||
<n-input v-model:value="formData.baseUrl" placeholder="请输入API的基础URL" />
|
||||
</n-form-item>
|
||||
|
||||
<NotesCollapse title="注意事项(必看!!!)" :default-expanded="true">
|
||||
<div class="notes-content">
|
||||
<p>
|
||||
<strong>1. 接口兼容性要求:</strong>自定义API必须兼容
|
||||
<span
|
||||
@click="openExternalLink('https://apiai.apifox.cn/folder-31977042')"
|
||||
class="clickable-link"
|
||||
>midjourney-proxy-plus</span
|
||||
>
|
||||
的接口规范,否则将无法正常工作。
|
||||
</p>
|
||||
<p>
|
||||
<strong>2. 基础URL说明:</strong>只需填写服务器的基础URL (例如: https://api.example.com),不需要包含路径。
|
||||
</p>
|
||||
<p>
|
||||
<strong>3. 技术支持声明:</strong>请注意,自定义的API配置属于个性化设置,我们不提供关于自定义的API的技术支持。
|
||||
</p>
|
||||
<p>
|
||||
<strong>4. 详细教程:</strong>请参考我们的
|
||||
<span
|
||||
@click="
|
||||
openExternalLink('https://rvgyir5wk1c.feishu.cn/wiki/OEj7wIdD6ivvCAkez4OcUPLcnIf')
|
||||
"
|
||||
class="clickable-link"
|
||||
>详细文档教程</span
|
||||
>
|
||||
获取完整的配置指南。
|
||||
</p>
|
||||
</div>
|
||||
</NotesCollapse>
|
||||
|
||||
<n-form-item>
|
||||
<n-button
|
||||
type="error"
|
||||
@click="handleDelete"
|
||||
style="min-width: 120px; margin-top: 20px; margin-right: 10px"
|
||||
>
|
||||
删除选中
|
||||
</n-button>
|
||||
<n-button type="primary" @click="handleSave" style="min-width: 120px; margin-top: 20px">
|
||||
保存配置
|
||||
</n-button>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
</n-space>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted, computed } from 'vue'
|
||||
import { useMessage } from 'naive-ui'
|
||||
import { OptionKeyName, OptionType } from '@/define/enum/option'
|
||||
import { isEmpty } from 'lodash'
|
||||
import { ValidateJson, ValidateJsonAndParse } from '@/define/Tools/validate'
|
||||
import { ValidateErrorString } from '@/renderer/src/common/validateError'
|
||||
|
||||
const message = useMessage()
|
||||
const formRef = ref(null)
|
||||
|
||||
// 配置列表
|
||||
const configList = ref([])
|
||||
const selectedConfig = ref(null)
|
||||
|
||||
// 简化后的表单数据结构
|
||||
const formData = reactive({
|
||||
id: null,
|
||||
name: '',
|
||||
baseUrl: ''
|
||||
})
|
||||
|
||||
// 简化后的表单验证规则
|
||||
const rules = {
|
||||
name: {
|
||||
required: true,
|
||||
message: '请输入设置名称',
|
||||
trigger: 'blur'
|
||||
},
|
||||
baseUrl: {
|
||||
required: true,
|
||||
message: '请输入基础URL',
|
||||
trigger: 'blur'
|
||||
}
|
||||
}
|
||||
|
||||
// 将配置列表转换为下拉选项格式
|
||||
const configOptions = computed(() => {
|
||||
const options = configList.value.map((item) => ({
|
||||
label: item.name,
|
||||
value: item.id
|
||||
}))
|
||||
|
||||
// 添加一个新建选项
|
||||
options.unshift({
|
||||
label: '-- 新建配置 --',
|
||||
value: 'new'
|
||||
})
|
||||
|
||||
return options
|
||||
})
|
||||
|
||||
// 获取配置列表
|
||||
const fetchConfigList = async () => {
|
||||
try {
|
||||
// 这里应该是从API或存储中获取配置列表
|
||||
let res = await window.options.GetOptionByKey(OptionKeyName.MJ_CustomAPISetting)
|
||||
if (res.code != 1) {
|
||||
throw new Error(res.message)
|
||||
}
|
||||
if (
|
||||
res.data == null ||
|
||||
res.data.value == null ||
|
||||
isEmpty(res.data.value) ||
|
||||
!ValidateJson(res.data.value)
|
||||
) {
|
||||
configList.value = []
|
||||
return
|
||||
}
|
||||
|
||||
configList.value = ValidateJsonAndParse(res.data.value)
|
||||
} catch (error) {
|
||||
message.error('获取配置列表失败')
|
||||
console.error(error)
|
||||
}
|
||||
}
|
||||
|
||||
// 处理配置选择变化
|
||||
const handleConfigChange = (value) => {
|
||||
if (value === 'new') {
|
||||
// 清空表单,准备创建新配置 - 使用新的数据结构
|
||||
Object.assign(formData, {
|
||||
id: null,
|
||||
name: '',
|
||||
baseUrl: ''
|
||||
})
|
||||
} else {
|
||||
// 加载选中的配置
|
||||
const config = configList.value.find((item) => item.id === value)
|
||||
if (config) {
|
||||
Object.assign(formData, { ...config })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 删除自定义配置
|
||||
async function handleDelete() {
|
||||
if (formData == null || formData.id == null) {
|
||||
message.error('请先选择要删除的配置')
|
||||
return
|
||||
}
|
||||
// 开始删除
|
||||
let findIndex = configList.value.findIndex((item) => item.id === formData.id)
|
||||
if (findIndex === -1) {
|
||||
message.error('删除的配置不存在,请重新选择')
|
||||
return
|
||||
}
|
||||
|
||||
configList.value.splice(findIndex, 1)
|
||||
let res = await window.options.ModifyOptionByKey(
|
||||
OptionKeyName.MJ_CustomAPISetting,
|
||||
JSON.stringify(configList.value),
|
||||
OptionType.JOSN
|
||||
)
|
||||
if (res.code != 1) {
|
||||
message.error('删除配置失败,' + res.message)
|
||||
return
|
||||
}
|
||||
message.success('删除配置成功')
|
||||
// 重置 - 使用新的数据结构
|
||||
Object.assign(formData, {
|
||||
id: null,
|
||||
name: '',
|
||||
baseUrl: ''
|
||||
})
|
||||
selectedConfig.value = null
|
||||
}
|
||||
|
||||
// 保存配置
|
||||
const handleSave = (e) => {
|
||||
e.preventDefault()
|
||||
formRef.value?.validate(async (errors) => {
|
||||
if (!errors) {
|
||||
try {
|
||||
// 这里应该是保存配置到API或存储
|
||||
if (!formData.id) {
|
||||
// 新增
|
||||
formData.id = crypto.randomUUID()
|
||||
configList.value.push({ ...formData })
|
||||
} else {
|
||||
// 修改原有的
|
||||
const index = configList.value.findIndex((item) => item.id === formData.id)
|
||||
if (index !== -1) {
|
||||
configList.value[index] = { ...formData }
|
||||
} else {
|
||||
throw new Error('配置不存在,请新增配置')
|
||||
}
|
||||
}
|
||||
|
||||
// 开始保存
|
||||
let res = await window.options.ModifyOptionByKey(
|
||||
OptionKeyName.MJ_CustomAPISetting,
|
||||
JSON.stringify(configList.value),
|
||||
OptionType.JOSN
|
||||
)
|
||||
if (res.code != 1) {
|
||||
throw new Error(res.message)
|
||||
}
|
||||
|
||||
// 刷新配置列表
|
||||
await fetchConfigList()
|
||||
|
||||
// 选中新创建/更新的配置
|
||||
selectedConfig.value = formData.id
|
||||
message.success('保存配置成功')
|
||||
} catch (error) {
|
||||
message.error('保存配置失败,' + error.message)
|
||||
}
|
||||
} else {
|
||||
let res = ValidateErrorString(errors)
|
||||
message.error(res)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开外部链接
|
||||
* @param {string} url - 要打开的URL
|
||||
*/
|
||||
function openExternalLink(url) {
|
||||
window.api.OpenUrl(url)
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
fetchConfigList()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.custom-mj-api-setting {
|
||||
padding: 20px;
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
:deep(.n-input) {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,286 @@
|
||||
<template>
|
||||
<div class="custom-mj-api-setting">
|
||||
<n-space vertical size="large">
|
||||
<n-select
|
||||
v-model:value="selectedConfig"
|
||||
placeholder="选择要编辑的配置"
|
||||
:options="configOptions"
|
||||
@update:value="handleConfigChange"
|
||||
/>
|
||||
|
||||
<n-form
|
||||
ref="formRef"
|
||||
:model="formData"
|
||||
:rules="rules"
|
||||
label-placement="left"
|
||||
label-width="120px"
|
||||
require-mark-placement="right-hanging"
|
||||
>
|
||||
<n-form-item label="设置名称" path="name">
|
||||
<n-input v-model:value="formData.name" placeholder="请输入设置名称" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="基础URL" path="baseUrl">
|
||||
<n-input v-model:value="formData.baseUrl" placeholder="请输入API的基础URL" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="代理地址" path="proxyUrl">
|
||||
<n-input v-model:value="formData.proxyUrl" placeholder="可选,输入图片代理服务器地址" />
|
||||
</n-form-item>
|
||||
|
||||
<NotesCollapse title="注意事项(必看!!!)" :default-expanded="true">
|
||||
<div class="notes-content">
|
||||
<p>
|
||||
<strong>1. 接口兼容性要求:</strong>自定义API必须兼容
|
||||
<span
|
||||
@click="openExternalLink('https://apiai.apifox.cn/folder-31977042')"
|
||||
class="clickable-link"
|
||||
>midjourney-proxy-plus</span
|
||||
>
|
||||
的接口规范,否则将无法正常工作。
|
||||
</p>
|
||||
<p>
|
||||
<strong>2. 基础URL说明:</strong>只需填写服务器的基础URL (例如:
|
||||
https://api.example.com),不需要包含路径。
|
||||
</p>
|
||||
<p>
|
||||
<strong>3. 代理地址说明:</strong
|
||||
>如果您的API需要通过代理访问,可以填写代理服务器地址,比如:https://cdn.laitool.cn,不需要则留空。
|
||||
</p>
|
||||
<p>
|
||||
<strong>4. 技术支持声明:</strong
|
||||
>请注意,自定义的生图包配置属于个性化设置,我们不提供关于任何生图包的技术支持。
|
||||
</p>
|
||||
<p>
|
||||
<strong>5. 详细教程:</strong>请参考我们的
|
||||
<span
|
||||
@click="
|
||||
openExternalLink('https://rvgyir5wk1c.feishu.cn/wiki/OEj7wIdD6ivvCAkez4OcUPLcnIf')
|
||||
"
|
||||
class="clickable-link"
|
||||
>详细文档教程</span
|
||||
>
|
||||
获取完整的配置指南。
|
||||
</p>
|
||||
</div>
|
||||
</NotesCollapse>
|
||||
|
||||
<n-form-item>
|
||||
<n-button
|
||||
type="error"
|
||||
@click="handleDelete"
|
||||
style="min-width: 120px; margin-top: 20px; margin-right: 10px"
|
||||
>
|
||||
删除选中
|
||||
</n-button>
|
||||
<n-button type="primary" @click="handleSave" style="min-width: 120px; margin-top: 20px">
|
||||
保存配置
|
||||
</n-button>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
</n-space>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted, computed } from 'vue'
|
||||
import { useMessage } from 'naive-ui'
|
||||
import { OptionKeyName, OptionType } from '@/define/enum/option'
|
||||
import { isEmpty } from 'lodash'
|
||||
import { ValidateJson, ValidateJsonAndParse } from '@/define/Tools/validate'
|
||||
import { ValidateErrorString } from '@/renderer/src/common/validateError'
|
||||
|
||||
const message = useMessage()
|
||||
const formRef = ref(null)
|
||||
|
||||
// 配置列表
|
||||
const configList = ref([])
|
||||
const selectedConfig = ref(null)
|
||||
|
||||
// 简化后的表单数据结构,添加了代理地址字段
|
||||
const formData = reactive({
|
||||
id: null,
|
||||
name: '',
|
||||
baseUrl: '',
|
||||
proxyUrl: '' // 新增代理地址字段,可以为空
|
||||
})
|
||||
|
||||
// 简化后的表单验证规则
|
||||
const rules = {
|
||||
name: {
|
||||
required: true,
|
||||
message: '请输入设置名称',
|
||||
trigger: 'blur'
|
||||
},
|
||||
baseUrl: {
|
||||
required: true,
|
||||
message: '请输入基础URL',
|
||||
trigger: 'blur'
|
||||
}
|
||||
}
|
||||
|
||||
// 将配置列表转换为下拉选项格式
|
||||
const configOptions = computed(() => {
|
||||
const options = configList.value.map((item) => ({
|
||||
label: item.name,
|
||||
value: item.id
|
||||
}))
|
||||
|
||||
// 添加一个新建选项
|
||||
options.unshift({
|
||||
label: '-- 新建配置 --',
|
||||
value: 'new'
|
||||
})
|
||||
|
||||
return options
|
||||
})
|
||||
|
||||
// 获取配置列表
|
||||
const fetchConfigList = async () => {
|
||||
try {
|
||||
// 这里应该是从API或存储中获取配置列表
|
||||
let res = await window.options.GetOptionByKey(OptionKeyName.MJ_CustomPackageSetting)
|
||||
if (res.code != 1) {
|
||||
throw new Error(res.message)
|
||||
}
|
||||
if (
|
||||
res.data == null ||
|
||||
res.data.value == null ||
|
||||
isEmpty(res.data.value) ||
|
||||
!ValidateJson(res.data.value)
|
||||
) {
|
||||
configList.value = []
|
||||
return
|
||||
}
|
||||
|
||||
configList.value = ValidateJsonAndParse(res.data.value)
|
||||
} catch (error) {
|
||||
message.error('获取配置列表失败')
|
||||
console.error(error)
|
||||
}
|
||||
}
|
||||
|
||||
// 处理配置选择变化
|
||||
const handleConfigChange = (value) => {
|
||||
if (value === 'new') {
|
||||
// 清空表单,准备创建新配置 - 使用新的数据结构
|
||||
Object.assign(formData, {
|
||||
id: null,
|
||||
name: '',
|
||||
baseUrl: '',
|
||||
proxyUrl: '' // 重置代理地址
|
||||
})
|
||||
} else {
|
||||
// 加载选中的配置
|
||||
const config = configList.value.find((item) => item.id === value)
|
||||
if (config) {
|
||||
Object.assign(formData, { ...config })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 删除自定义配置
|
||||
async function handleDelete() {
|
||||
if (formData == null || formData.id == null) {
|
||||
message.error('请先选择要删除的配置')
|
||||
return
|
||||
}
|
||||
// 开始删除
|
||||
let findIndex = configList.value.findIndex((item) => item.id === formData.id)
|
||||
if (findIndex === -1) {
|
||||
message.error('删除的配置不存在,请重新选择')
|
||||
return
|
||||
}
|
||||
|
||||
configList.value.splice(findIndex, 1)
|
||||
let res = await window.options.ModifyOptionByKey(
|
||||
OptionKeyName.MJ_CustomPackageSetting,
|
||||
JSON.stringify(configList.value),
|
||||
OptionType.JOSN
|
||||
)
|
||||
if (res.code != 1) {
|
||||
message.error('删除配置失败,' + res.message)
|
||||
return
|
||||
}
|
||||
message.success('删除配置成功')
|
||||
// 重置 - 使用新的数据结构
|
||||
Object.assign(formData, {
|
||||
id: null,
|
||||
name: '',
|
||||
baseUrl: '',
|
||||
proxyUrl: '' // 重置代理地址
|
||||
})
|
||||
selectedConfig.value = null
|
||||
}
|
||||
|
||||
// 保存配置
|
||||
const handleSave = (e) => {
|
||||
e.preventDefault()
|
||||
formRef.value?.validate(async (errors) => {
|
||||
if (!errors) {
|
||||
try {
|
||||
// 这里应该是保存配置到API或存储
|
||||
if (!formData.id) {
|
||||
// 新增
|
||||
formData.id = crypto.randomUUID()
|
||||
configList.value.push({ ...formData })
|
||||
} else {
|
||||
// 修改原有的
|
||||
const index = configList.value.findIndex((item) => item.id === formData.id)
|
||||
if (index !== -1) {
|
||||
configList.value[index] = { ...formData }
|
||||
} else {
|
||||
throw new Error('配置不存在,请新增配置')
|
||||
}
|
||||
}
|
||||
|
||||
// 开始保存
|
||||
let res = await window.options.ModifyOptionByKey(
|
||||
OptionKeyName.MJ_CustomPackageSetting,
|
||||
JSON.stringify(configList.value),
|
||||
OptionType.JOSN
|
||||
)
|
||||
if (res.code != 1) {
|
||||
throw new Error(res.message)
|
||||
}
|
||||
|
||||
// 刷新配置列表
|
||||
await fetchConfigList()
|
||||
|
||||
// 选中新创建/更新的配置
|
||||
selectedConfig.value = formData.id
|
||||
message.success('保存配置成功')
|
||||
} catch (error) {
|
||||
message.error('保存配置失败,' + error.message)
|
||||
}
|
||||
} else {
|
||||
let res = ValidateErrorString(errors)
|
||||
message.error(res)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开外部链接
|
||||
* @param {string} url - 要打开的URL
|
||||
*/
|
||||
function openExternalLink(url) {
|
||||
window.api.OpenUrl(url)
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
fetchConfigList()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.custom-mj-api-setting {
|
||||
padding: 20px;
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
:deep(.n-input) {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
@@ -50,6 +50,9 @@
|
||||
style="width: 100px"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item style="margin-left: 10px" path="mj_api_url">
|
||||
<n-button @click="CustomMJAPI">自定义MJ API</n-button>
|
||||
</n-form-item>
|
||||
</div>
|
||||
</n-form>
|
||||
<NotesCollapse title="注意事项">
|
||||
@@ -79,22 +82,16 @@
|
||||
|
||||
<script setup>
|
||||
import { onMounted, ref } from 'vue'
|
||||
import {
|
||||
NCard,
|
||||
NForm,
|
||||
NFormItem,
|
||||
NInput,
|
||||
NSelect,
|
||||
NButton,
|
||||
useMessage,
|
||||
NIcon,
|
||||
NCollapse,
|
||||
NCollapseItem
|
||||
} from 'naive-ui'
|
||||
import { NCard, NForm, NFormItem, NInput, NSelect, NButton, useMessage, useDialog } from 'naive-ui'
|
||||
import { useOptionStore } from '@/stores/option'
|
||||
import MJDefine from '@/main/Service/MJ/mjDefine'
|
||||
import { isEmpty } from 'lodash'
|
||||
import NotesCollapse from '../../Common/NotesCollapse.vue'
|
||||
import CustomMJAPISetting from './CustomMJAPISetting.vue'
|
||||
import { GetMJUrlOptions } from '@/define/api/apiUrlDefine'
|
||||
import { OptionKeyName } from '@/define/enum/option'
|
||||
import { ValidateJson, ValidateJsonAndParse } from '@/define/Tools/validate'
|
||||
let dialog = useDialog()
|
||||
|
||||
let optionStore = useOptionStore()
|
||||
let message = useMessage()
|
||||
@@ -103,10 +100,55 @@ let mjAPIURLOptions = ref([])
|
||||
let mjImageSpeedOptions = ref([])
|
||||
|
||||
onMounted(() => {
|
||||
mjAPIURLOptions.value = MJDefine.GetMJAPIUrlOptions()
|
||||
GetAllAPIUrlOptions()
|
||||
mjImageSpeedOptions.value = MJDefine.GetMJSpeedOptions()
|
||||
})
|
||||
|
||||
async function GetAllAPIUrlOptions() {
|
||||
let defaultApiUrl = GetMJUrlOptions('api')
|
||||
let customApiUrl = []
|
||||
// 加载自定义的
|
||||
let customApiSettingString = await window.options.GetOptionByKey(
|
||||
OptionKeyName.MJ_CustomAPISetting
|
||||
)
|
||||
|
||||
if (customApiSettingString.code != 1) {
|
||||
throw new Error('获取自定义的API设置失败,请检查配置')
|
||||
}
|
||||
if (
|
||||
customApiSettingString.data == null ||
|
||||
isEmpty(customApiSettingString.data.value) ||
|
||||
!ValidateJson(customApiSettingString.data.value)
|
||||
) {
|
||||
customApiUrl = []
|
||||
} else {
|
||||
let customApiUrlList = ValidateJsonAndParse(customApiSettingString.data.value)
|
||||
if (customApiUrlList.length == 0) {
|
||||
customApiUrl = []
|
||||
} else {
|
||||
customApiUrlList.forEach((item) => {
|
||||
let baseUrl = item.baseUrl.replace(/\/$/, '')
|
||||
customApiUrl.push({
|
||||
label: item.name,
|
||||
value: item.id,
|
||||
isPackage: true,
|
||||
mj_url: {
|
||||
imagine: baseUrl + '/mj/submit/imagine',
|
||||
describe: baseUrl + '/mj/submit/describe',
|
||||
update_file: baseUrl + '/mj/submit/upload-discord-images',
|
||||
once_get_task: baseUrl + '/mj/task/${id}/fetch',
|
||||
query_url: null
|
||||
},
|
||||
buy_url: null
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
// 合并默认的和自定义的API地址
|
||||
mjAPIURLOptions.value = defaultApiUrl.concat(customApiUrl)
|
||||
console.log('mjAPIURLOptions', mjAPIURLOptions.value)
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开购买GPT的地址
|
||||
*/
|
||||
@@ -126,6 +168,22 @@ async function openGptBuyUrl() {
|
||||
}
|
||||
}
|
||||
|
||||
async function CustomMJAPI() {
|
||||
dialog.create({
|
||||
title: '自定义MJ API',
|
||||
maskClosable: false,
|
||||
content: () => h(CustomMJAPISetting, {}, {}),
|
||||
closable: true,
|
||||
showIcon: false,
|
||||
style: { width: '680px' },
|
||||
footer: null,
|
||||
onClose: async () => {
|
||||
// 关闭时刷新数据
|
||||
await GetAllAPIUrlOptions()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开外部链接
|
||||
* @param {string} url - 要打开的URL
|
||||
|
||||
@@ -2,10 +2,11 @@
|
||||
<n-card title="生图包设置" hoverable style="margin-top: 10px; min-width: 850px" size="medium">
|
||||
<n-form inline>
|
||||
<n-space align="center" :size="12">
|
||||
<n-form-item label="套餐选择">
|
||||
<n-form-item label="生图包选择">
|
||||
<n-select
|
||||
v-model:value="optionStore.MJ_GlobalSetting.mj_imagePackageSetting.selectPackage"
|
||||
:options="GetMJUrlOptions('package')"
|
||||
:options="imagePackageOptions"
|
||||
@update-value="handlePackageChange"
|
||||
placeholder="选择套餐"
|
||||
style="min-width: 200px"
|
||||
/>
|
||||
@@ -28,15 +29,19 @@
|
||||
<n-form-item label="出图代理">
|
||||
<n-select
|
||||
v-model:value="optionStore.MJ_GlobalSetting.mj_imagePackageSetting.selectedProxy"
|
||||
:options="ImagePackageProxyOptions"
|
||||
:options="imageProxyUrlOptions"
|
||||
placeholder="选择出图代理"
|
||||
style="min-width: 200px"
|
||||
/>
|
||||
</n-form-item>
|
||||
|
||||
<!-- <n-form-item>
|
||||
<n-form-item>
|
||||
<n-button @click="handleQuery"> 查询 </n-button>
|
||||
</n-form-item> -->
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item>
|
||||
<n-button @click="CustomImagePackage" > 自定义生图包 </n-button>
|
||||
</n-form-item>
|
||||
</n-space>
|
||||
</n-form>
|
||||
<NotesCollapse title="注意事项">
|
||||
@@ -44,10 +49,7 @@
|
||||
1. 使用生图包前,请确保您已完成套餐购买。<strong>未购买套餐将无法使用相关功能。</strong>
|
||||
</p>
|
||||
<p>2. 标准生图包最大并发数为3,具体并发数量以您所购买的套餐规格为准。</p>
|
||||
<p>3. 出图代理支持香港和美国节点选择,也兼容系统默认代理设置,与代理模式保持一致。</p>
|
||||
<p>
|
||||
4. 您可随时点击 <strong>"查询"</strong> 按钮,实时查看当前套餐已使用的出图数量及剩余额度。
|
||||
</p>
|
||||
<p>3. 可以选择出图包对应的图片代理,也兼容系统默认代理设置,与代理模式保持一致。</p>
|
||||
</NotesCollapse>
|
||||
</n-card>
|
||||
</template>
|
||||
@@ -56,12 +58,19 @@
|
||||
import { useMessage, NCard, NForm, NFormItem, NButton, NSelect, NInput, NSpace } from 'naive-ui'
|
||||
import { GetMJUrlOptions } from '@/define/api/apiUrlDefine'
|
||||
import { useOptionStore } from '@/stores/option'
|
||||
import { ImagePackageProxyOptions } from '@/define/data/settingData'
|
||||
import { isEmpty } from 'lodash'
|
||||
import NotesCollapse from '../../Common/NotesCollapse.vue'
|
||||
import CustomMJPackageSetting from './CustomMJPackageSetting.vue'
|
||||
import { OptionKeyName } from '@/define/enum/option'
|
||||
import { ValidateJson, ValidateJsonAndParse } from '@/define/Tools/validate'
|
||||
import { GetImageProxyUrlOptions } from '@/define/data/settingData'
|
||||
|
||||
const optionStore = useOptionStore()
|
||||
const message = useMessage()
|
||||
const dialog = useDialog()
|
||||
|
||||
let imagePackageOptions = ref([])
|
||||
let imageProxyUrlOptions = ref([])
|
||||
|
||||
/**
|
||||
* 打开购买网址
|
||||
@@ -99,6 +108,133 @@ const handleQuery = () => {
|
||||
window.api.OpenUrl(queryUrl)
|
||||
}
|
||||
}
|
||||
|
||||
// 修改处理选择变化的方法,添加明确的参数
|
||||
function handlePackageChange(value) {
|
||||
// 先更新store中的值
|
||||
optionStore.MJ_GlobalSetting.mj_imagePackageSetting.selectPackage = value
|
||||
// 然后使用最新选择的值来获取代理选项
|
||||
fetchImageProxyOptions(value)
|
||||
}
|
||||
|
||||
// 修改方法定义,使其接收当前选择的值作为参数
|
||||
function fetchImageProxyOptions(selectedPackage) {
|
||||
// 移除debugger,避免中断执行
|
||||
// 使用传入的参数作为当前选择的生图包
|
||||
let packageValue =
|
||||
selectedPackage || optionStore.MJ_GlobalSetting.mj_imagePackageSetting.selectPackage
|
||||
|
||||
let defaultImageProxyUrl = GetImageProxyUrlOptions(packageValue)
|
||||
|
||||
// 获取当前选中的生图包
|
||||
let findIndex = imagePackageOptions.value.findIndex((item) => item.value == packageValue)
|
||||
|
||||
if (findIndex == -1) {
|
||||
// 即使找不到对应包,也设置可用的代理选项
|
||||
imageProxyUrlOptions.value = defaultImageProxyUrl
|
||||
|
||||
// 如果有可用的代理选项,默认选择第一个
|
||||
// 修改条件判断,处理null、undefined、空字符串等所有假值情况
|
||||
if (
|
||||
defaultImageProxyUrl.length > 0 &&
|
||||
!optionStore.MJ_GlobalSetting.mj_imagePackageSetting.selectedProxy
|
||||
) {
|
||||
optionStore.MJ_GlobalSetting.mj_imagePackageSetting.selectedProxy =
|
||||
defaultImageProxyUrl[0].value
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
let selectPackage = imagePackageOptions.value[findIndex]
|
||||
// 确保 proxyUrl 存在才添加
|
||||
if (selectPackage.proxyUrl) {
|
||||
defaultImageProxyUrl.unshift({
|
||||
label: selectPackage.label + ' 图片代理',
|
||||
value: selectPackage.proxyUrl
|
||||
})
|
||||
}
|
||||
|
||||
imageProxyUrlOptions.value = defaultImageProxyUrl
|
||||
debugger
|
||||
// 判断当前选中的代理是不是在里面,不是的话重置选中代理
|
||||
let findProxyIndex = defaultImageProxyUrl.findIndex(
|
||||
(item) => item.value == optionStore.MJ_GlobalSetting.mj_imagePackageSetting.selectedProxy
|
||||
)
|
||||
|
||||
if (findProxyIndex == -1) {
|
||||
// 确保有默认值可以设置
|
||||
if (selectPackage.proxyUrl) {
|
||||
optionStore.MJ_GlobalSetting.mj_imagePackageSetting.selectedProxy = selectPackage.proxyUrl
|
||||
} else if (defaultImageProxyUrl.length > 0) {
|
||||
// 如果没有包专用代理,则使用第一个可用代理
|
||||
setTimeout(() => {
|
||||
optionStore.MJ_GlobalSetting.mj_imagePackageSetting.selectedProxy =
|
||||
defaultImageProxyUrl[0].value
|
||||
}, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 获取生图包 默认的和自定义的
|
||||
async function fetchImagePackageOptions() {
|
||||
let defaultApiUrl = GetMJUrlOptions('package')
|
||||
let customApiUrl = []
|
||||
// 加载自定义的
|
||||
let res = await window.options.GetOptionByKey(OptionKeyName.MJ_CustomPackageSetting)
|
||||
if (res.code != 1) {
|
||||
message.error('获取自定义的生图包设置失败,请检查配置')
|
||||
return
|
||||
}
|
||||
if (res.data == null || isEmpty(res.data.value) || !ValidateJson(res.data.value)) {
|
||||
imagePackageOptions.value = defaultApiUrl
|
||||
return
|
||||
}
|
||||
let customApiUrlList = ValidateJsonAndParse(res.data.value)
|
||||
if (customApiUrlList.length <= 0) {
|
||||
imagePackageOptions.value = defaultApiUrl
|
||||
return
|
||||
}
|
||||
customApiUrlList.forEach((element) => {
|
||||
let baseUrl = element.baseUrl.replace(/\/$/, '')
|
||||
customApiUrl.push({
|
||||
label: element.name,
|
||||
value: element.id,
|
||||
isPackage: true,
|
||||
mj_url: {
|
||||
imagine: baseUrl + '/mj/submit/imagine',
|
||||
describe: baseUrl + '/mj/submit/describe',
|
||||
update_file: baseUrl + '/mj/submit/upload-discord-images',
|
||||
once_get_task: baseUrl + '/mj/task/${id}/fetch',
|
||||
query_url: null
|
||||
},
|
||||
buy_url: null,
|
||||
proxyUrl: element.proxyUrl // 添加代理地址
|
||||
})
|
||||
})
|
||||
imagePackageOptions.value = defaultApiUrl.concat(customApiUrl)
|
||||
fetchImageProxyOptions()
|
||||
}
|
||||
|
||||
function CustomImagePackage() {
|
||||
dialog.create({
|
||||
title: '自定义生图包',
|
||||
content: () => h(CustomMJPackageSetting),
|
||||
style: {
|
||||
width: '680px'
|
||||
},
|
||||
closable: true,
|
||||
maskClosable: false,
|
||||
showIcon: false,
|
||||
onClose: async () => {
|
||||
await fetchImagePackageOptions()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
// 确保先完全加载包选项,再设置代理选项
|
||||
fetchImagePackageOptions()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
Reference in New Issue
Block a user