1. 修复MJ设置初始化问题
2. 添加MJ本地代理模式,可以本地部署的代理模式
This commit is contained in:
2025-04-02 19:52:57 +08:00
parent 927dd14574
commit c43abd6908
30 changed files with 1341 additions and 686 deletions
+79
View File
@@ -0,0 +1,79 @@
.custom-collapse {
margin-top: 16px;
border-radius: 6px;
background-color: rgba(255, 247, 231, 0.6);
border: 1px solid #ffe7a3;
overflow: hidden;
}
.collapse-header {
display: flex;
align-items: center;
font-weight: bold;
color: #b88230;
padding: 8px 0;
/* 增加上下内边距,使折叠状态下的高度更高 */
font-size: 16px;
/* 增加字体大小 */
}
.collapse-header .warning-icon {
margin-right: 8px;
color: #e6a23c;
}
/* 为Naive UI的折叠面板标题添加额外的样式 */
:deep(.n-collapse-item__header) {
padding: 12px 20px !important;
/* 覆盖原有内边距 */
height: auto !important;
/* 允许高度自适应内容 */
}
:deep(.n-collapse-item__header-main) {
display: flex;
align-items: center;
}
.notes-section {
margin-top: 16px;
padding: 12px;
border-radius: 6px;
background-color: rgba(255, 247, 231, 0.6);
border: 1px solid #ffe7a3;
}
.notes-title {
display: flex;
align-items: center;
font-size: 16px;
font-weight: bold;
margin-top: 0;
margin-bottom: 8px;
color: #b88230;
}
.warning-icon {
margin-right: 6px;
color: #e6a23c;
}
.notes-content {
padding-left: 24px;
}
.notes-content p {
margin: 4px 0;
color: #5c3c10;
}
.clickable-link {
color: #0077ff;
text-decoration: underline;
cursor: pointer;
transition: color 0.2s ease;
}
.clickable-link:hover {
color: #0055cc;
}
@@ -0,0 +1,140 @@
<!-- filepath: src\renderer\src\components\Common\NotesCollapse.vue -->
<template>
<n-collapse class="custom-collapse">
<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">
<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>
<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>
<script setup>
import { NCollapse, NCollapseItem, NIcon } from 'naive-ui'
defineProps({
// 折叠面板名称
name: {
type: [String, Number],
default: '1'
},
// 标题
title: {
type: String,
default: '注意事项'
},
// 图标类型: 'warning', 'info' 或自定义
iconType: {
type: String,
default: 'warning'
},
// 内容项数组,每项会渲染为一个段落
items: {
type: Array,
default: () => []
}
})
</script>
<style scoped>
.custom-collapse {
margin-top: 16px;
border-radius: 6px;
background-color: rgba(255, 247, 231, 0.6);
border: 1px solid #ffe7a3;
overflow: hidden;
}
.collapse-header {
display: flex;
align-items: center;
font-weight: bold;
color: #b88230;
padding: 8px 0;
/* 增加上下内边距,使折叠状态下的高度更高 */
font-size: 16px;
/* 增加字体大小 */
}
.collapse-header .warning-icon {
margin-right: 8px;
color: #e6a23c;
}
/* 为Naive UI的折叠面板标题添加额外的样式 */
:deep(.n-collapse-item__header) {
padding: 12px 20px !important;
/* 覆盖原有内边距 */
height: auto !important;
/* 允许高度自适应内容 */
}
:deep(.n-collapse-item__header-main) {
display: flex;
align-items: center;
}
.notes-section {
margin-top: 16px;
padding: 12px;
border-radius: 6px;
background-color: rgba(255, 247, 231, 0.6);
border: 1px solid #ffe7a3;
}
.notes-title {
display: flex;
align-items: center;
font-size: 16px;
font-weight: bold;
margin-top: 0;
margin-bottom: 8px;
color: #b88230;
}
.warning-icon {
margin-right: 6px;
color: #e6a23c;
}
.notes-content {
padding-left: 24px;
}
.notes-content p {
margin: 4px 0;
color: #5c3c10;
}
.clickable-link {
color: #0077ff;
text-decoration: underline;
cursor: pointer;
transition: color 0.2s ease;
}
.clickable-link:hover {
color: #0055cc;
}
</style>
@@ -3,7 +3,7 @@
<div id="AddMultiRemoteMj" style="overflow-y: auto">
<div style="margin-bottom: 5px">
<n-button type="info" @click="ManageAccount(null)">新增账号</n-button>
<n-button type="info" style="margin-left: 10px" @click="GetRemoteMJSettingsFromService()"
<n-button type="info" style="margin-left: 10px" @click="GetRemoteMJSettingsFromService"
>同步服务器帐号信息</n-button
>
</div>
@@ -25,8 +25,13 @@ let props = defineProps({
height: {
type: Number,
default: 500
},
type: {
type: String,
default: 'remote'
}
})
let message = useMessage()
let dialog = useDialog()
let maxHeight = ref(props.height - 150)
@@ -37,7 +42,7 @@ let spinning = ref(false)
async function GetRemoteMJSettingsFromService() {
spinning.value = true
try {
let remoteMjSettingRes = await window.setting.GetRemoteMJSettingsFromService()
let remoteMjSettingRes = await window.setting.GetRemoteMJSettingsFromService(props.type)
if (remoteMjSettingRes.code == 0) {
message.error('获取代理MJ配置失败')
return
@@ -45,7 +50,7 @@ async function GetRemoteMJSettingsFromService() {
message.success('同步服务器帐号信息成功')
// 关闭的时候,刷新数据
let res = await window.setting.GetRemoteMJSettings()
let res = await window.setting.GetRemoteMJSettings(props.type)
if (res.code == 0) {
message.error('获取代理MJ配置失败')
} else {
@@ -146,7 +151,7 @@ onMounted(async () => {
spinning.value = true
try {
let res = await window.setting.GetRemoteMJSettings()
let res = await window.setting.GetRemoteMJSettings(props.type)
console.log(res)
if (res.code == 0) {
message.error('获取代理MJ配置失败')
@@ -176,12 +181,12 @@ async function ManageAccount(remote = null) {
dialog.create({
showIcon: false,
title: '添加MJ账号',
content: () => h(ManageRemoteMjAccount, {}),
content: () => h(ManageRemoteMjAccount, { type: props.type }),
style: `min-width : 600px; width : ${dW}px; height : ${dH}px; padding-right : 5px;`,
maskClosable: false,
onClose: async () => {
// 关闭的时候,刷新数据
let remoteMjSettingRes = await window.setting.GetRemoteMJSettings()
let remoteMjSettingRes = await window.setting.GetRemoteMJSettings(props.type)
if (remoteMjSettingRes.code == 0) {
message.error('获取代理MJ配置失败')
} else {
@@ -216,7 +221,7 @@ async function DeleteAccount(row, isRemote) {
}
message.success('删除账号成功')
// 这边刷新一下数据
let remoteMjSettingRes = await window.setting.GetRemoteMJSettings()
let remoteMjSettingRes = await window.setting.GetRemoteMJSettings(props.type)
if (remoteMjSettingRes.code == 0) {
message.error('获取代理MJ配置失败')
} else {
@@ -102,74 +102,72 @@
</div>
</template>
<script>
<script setup>
import { ref, onMounted, defineComponent, onUnmounted, toRaw, watch } from 'vue'
import { useMessage, NForm, NFormItem, NInput, NInputNumber, NButton, NSwitch } from 'naive-ui'
import { useSettingStore } from '../../../../../stores/setting'
export default defineComponent({
components: {
NForm,
NFormItem,
NInput,
NInputNumber,
NButton,
NSwitch
},
setup() {
let message = useMessage()
let settingStore = useSettingStore()
let addRef = ref(null)
let loading = ref(false)
let message = useMessage()
onMounted(async () => {
console.log(settingStore)
})
let rules = {
guildId: [{ required: true, message: '请输入服务器ID', trigger: 'blur' }],
channelId: [{ required: true, message: '请输入频道ID', trigger: 'blur' }],
userToken: [{ required: true, message: '请输入用户token', trigger: 'blur' }]
}
let settingStore = useSettingStore()
let addRef = ref(null)
let loading = ref(false)
/**
* 创建账号
*/
async function CreateAccount(e) {
e.preventDefault()
addRef.value?.validate(async (errors) => {
if (errors) {
message.error('请检查必填字段')
return
}
loading.value = true
// 判断当前是不是有数据
if (settingStore.actionRemoteMJ.accountId) {
// 同步并重连
let res = await window.setting.UpdateRemoteMJSetting(toRaw(settingStore.actionRemoteMJ))
loading.value = false
if (res.code == 0) {
message.error('更新账号失败,错误消息如下:' + res.message)
return
}
message.success('更新账号成功')
} else {
// 新建,开始保存
let res = await window.setting.AddRemoteMJSetting(toRaw(settingStore.actionRemoteMJ),true)
loading.value = false
if (res.code == 0) {
message.error('创建账号失败,错误消息如下:' + res.message)
return
}
message.success('创建账号成功')
settingStore.ResetActionRemoteMJ()
}
})
}
return { settingStore, rules, CreateAccount, addRef, loading }
let props = defineProps({
type: {
type: String,
default: 'remote'
}
})
onMounted(async () => {
console.log(settingStore)
})
let rules = {
guildId: [{ required: true, message: '请输入服务器ID', trigger: 'blur' }],
channelId: [{ required: true, message: '请输入频道ID', trigger: 'blur' }],
userToken: [{ required: true, message: '请输入用户token', trigger: 'blur' }]
}
/**
* 创建账号
*/
async function CreateAccount(e) {
e.preventDefault()
addRef.value?.validate(async (errors) => {
if (errors) {
message.error('请检查必填字段')
return
}
loading.value = true
// 判断当前是不是有数据
if (settingStore.actionRemoteMJ.accountId) {
// 同步并重连
let res = await window.setting.UpdateRemoteMJSetting(
toRaw(settingStore.actionRemoteMJ),
props.type
)
loading.value = false
if (res.code == 0) {
message.error('更新账号失败,错误消息如下:' + res.message)
return
}
message.success('更新账号成功')
} else {
// 新建,开始保存
let res = await window.setting.AddRemoteMJSetting(
toRaw(settingStore.actionRemoteMJ),
props.type
)
loading.value = false
if (res.code == 0) {
message.error('创建账号失败,错误消息如下:' + res.message)
return
}
message.success('创建账号成功')
settingStore.ResetActionRemoteMJ()
}
})
}
</script>
@@ -52,16 +52,49 @@
</n-form-item>
</div>
</n-form>
<NotesCollapse title="注意事项">
<p>
1. 使用
<strong>无需科学上网</strong>支持香港和美国节点香港节点对大陆做了优化延迟
<strong>100ms</strong> 以内
</p>
<p>2. 提供 <strong>快速</strong> <strong>慢速</strong> 两种出图方式可根据需求选择</p>
<p>3. 支持 <strong>20并发请求</strong>可同时处理多张图片生成任务大大提高工作效率</p>
<p>
4. 开启 <strong>"国内转发"</strong> 选项可解决部分地区如河南福建等的网络访问问题
</p>
<p>
5. 确保网络环境稳定以保证服务正常运行推荐稳定🪜:
<span
class="clickable-link"
@click="openExternalLink('https://justmysocks.net/members/aff.php?aff=17835')"
>
Just My Socks网络加速服务
</span>
</p>
</NotesCollapse>
</n-card>
</div>
</template>
<script setup>
import { onMounted, ref } from 'vue'
import { NCard, NForm, NFormItem, NInput, NSelect, NButton, useMessage } from 'naive-ui'
import {
NCard,
NForm,
NFormItem,
NInput,
NSelect,
NButton,
useMessage,
NIcon,
NCollapse,
NCollapseItem
} 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'
let optionStore = useOptionStore()
let message = useMessage()
@@ -92,4 +125,15 @@ async function openGptBuyUrl() {
window.api.OpenUrl(buy_url)
}
}
/**
* 打开外部链接
* @param {string} url - 要打开的URL
*/
function openExternalLink(url) {
window.api.OpenUrl(url)
}
</script>
<style scoped>
@import '../../../assets//css//note.less';
</style>
@@ -0,0 +1,124 @@
<template>
<div class="mj-remote-setting">
<n-card title="本地代理模式设置-自行部署服务" hoverable style="margin-top: 10px; min-width: 850px">
<n-form inline :model="optionStore.MJ_GlobalSetting.mj_localRemoteSimpleSetting">
<n-form-item label="服务地址" path="baseUrl">
<n-input
v-model:value="optionStore.MJ_GlobalSetting.mj_localRemoteSimpleSetting.baseUrl"
placeholder="输入服务器地址"
style="width: 200px"
/>
</n-form-item>
<n-form-item label="端口" path="port">
<n-input
v-model:value="optionStore.MJ_GlobalSetting.mj_localRemoteSimpleSetting.port"
placeholder="输入端口号"
style="width: 120px"
/>
</n-form-item>
<n-form-item path="token">
<template #label>
<span style="display: flex; align-items: center">
<span>访问令牌</span>
<n-tooltip trigger="hover" placement="top">
<template #trigger>
<n-icon size="18" class="question-icon">
<svg 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 10s10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8s8 3.59 8 8s-3.59 8-8 8zm-1-4h2v2h-2zm1.61-9.96c-2.06-.3-3.88.97-4.43 2.79c-.18.58.26 1.17.87 1.17h.2c.41 0 .74-.29.88-.67c.32-.89 1.27-1.5 2.3-1.28c.95.2 1.65 1.13 1.57 2.1c-.1 1.34-1.62 1.63-2.45 2.88c0 .01-.01.01-.01.02c-.01.02-.02.03-.03.05c-.09.15-.18.32-.25.5c-.16.39-.22.82-.22 1.28h2c0-.42.11-.77.28-1.07c.53-.9 1.77-1.41 2.53-2.43c.8-1.05.76-2.46.28-3.55c-.87-1.98-2.9-3.12-4.52-2.79z"
></path>
</svg>
</n-icon>
</template>
默认值admin
</n-tooltip>
</span>
</template>
<n-input
v-model:value="optionStore.MJ_GlobalSetting.mj_localRemoteSimpleSetting.token"
placeholder="输入访问令牌"
style="width: 200px"
/>
</n-form-item>
<n-form-item style="margin-left: 20px">
<n-button type="info" @click="AddMultiMjAccount">账号管理</n-button>
</n-form-item>
</n-form>
<NotesCollapse title="注意事项">
<p>
1. 本地代理模式支持本地部署和服务器部署需要自己进行部署<span
class="clickable-link"
@click="openExternalLink('https://rvgyir5wk1c.feishu.cn/wiki/N7uuwsO5piB8F6kpvDScUNBGnpd')"
>
本地代理模式部署教程
</span>
</p>
<p>2. 访问令牌默认为 <strong>admin</strong>如有修改请相应更新</p>
<p>3. 通过账号管理功能可添加多个MJ账号实现任务并行处理提高效率</p>
<p>
4. 确保网络环境稳定以保证服务正常运行推荐稳定🪜:
<span
class="clickable-link"
@click="openExternalLink('https://justmysocks.net/members/aff.php?aff=17835')"
>
Just My Socks网络加速服务
</span>
</p>
</NotesCollapse>
</n-card>
</div>
</template>
<script setup>
import { ref, h } from 'vue'
import {
NCard,
NButton,
useDialog,
NForm,
NFormItem,
NInput,
useMessage,
NTooltip,
NIcon
} from 'naive-ui'
import AddMultiRemoteMj from '../Components/AddMultiRemoteMj.vue'
import { useOptionStore } from '@/stores/option'
import NotesCollapse from '../../Common/NotesCollapse.vue'
const optionStore = useOptionStore()
const dialog = useDialog()
const message = useMessage()
/**
* 添加多个账号,这样可以同时跑多个账号
*/
async function AddMultiMjAccount() {
let dW = window.innerWidth * 0.9
let dH = window.innerHeight * 0.9
dialog.create({
showIcon: false,
title: '管理代理模式MJ账号',
content: () => h(AddMultiRemoteMj, { height: dH, type: 'local' }),
style: `min-width : 600px; width : ${dW}px; height : ${dH}px; padding-right : 5px;`,
maskClosable: false
})
}
/**
* 打开外部链接
* @param {string} url - 要打开的URL
*/
function openExternalLink(url) {
window.api.OpenUrl(url)
}
</script>
<style scoped>
@import '../../../assets//css//note.less';
</style>
@@ -17,19 +17,36 @@
<n-button type="info" @click="AddMultiMjAccount">账号管理</n-button>
</n-form-item>
</n-form>
<NotesCollapse title="注意事项">
<p>1. 日常使用无需开启梯子仅添加账号时需要网络代理</p>
<p>2. 通过账号管理功能可添加多个MJ账号实现任务并行处理提高效率</p>
<p>
3. 开启 <strong>"国内转发"</strong> 选项可解决部分地区如河南福建等的网络访问问题
</p>
<p>
4. 确保网络环境稳定以保证服务正常运行推荐稳定🪜:
<span
class="clickable-link"
@click="openExternalLink('https://justmysocks.net/members/aff.php?aff=17835')"
>
Just My Socks网络加速服务
</span>
</p>
</NotesCollapse>
</n-card>
</div>
</template>
<script setup>
import { ref, h } from 'vue'
import { NCard, NButton, useDialog, NForm, NFormItem, NSelect } from 'naive-ui'
import { NCard, NButton, useDialog, NForm, NFormItem, NSelect, useMessage } from 'naive-ui'
import AddMultiRemoteMj from '../Components/AddMultiRemoteMj.vue'
import { useOptionStore } from '@/stores/option'
import NotesCollapse from '../../Common/NotesCollapse.vue'
let optionStore = useOptionStore()
let dialog = useDialog()
const optionStore = useOptionStore()
const dialog = useDialog()
const message = useMessage()
/**
* 添加多个账号,这样可以同时跑多个账号
@@ -40,9 +57,21 @@ async function AddMultiMjAccount() {
dialog.create({
showIcon: false,
title: '管理代理模式MJ账号',
content: () => h(AddMultiRemoteMj, { height: dH }),
content: () => h(AddMultiRemoteMj, { height: dH, type: 'remote' }),
style: `min-width : 600px; width : ${dW}px; height : ${dH}px; padding-right : 5px;`,
maskClosable: false
})
}
/**
* 打开外部链接
* @param {string} url - 要打开的URL
*/
function openExternalLink(url) {
window.api.OpenUrl(url)
}
</script>
<style scoped>
@import '../../../assets//css//note.less';
</style>
@@ -3,7 +3,8 @@
<MJSimpleSetting />
<MJAPISetting />
<MJRemoteSetting />
<MJBrowserSetting />
<!-- <MJBrowserSetting /> -->
<MJLocalRemoteSetting />
<n-button type="info" @click="SaveMjSetting" style="margin-top: 10px">保存MJ配置</n-button>
</div>
</template>
@@ -19,6 +20,7 @@ import MJSimpleSetting from './MJSimpleSetting.vue'
import MJAPISetting from './MJAPISetting.vue'
import MJRemoteSetting from './MJRemoteSetting.vue'
import MJBrowserSetting from './MJBrowserSetting.vue'
import MJLocalRemoteSetting from './MJLocalRemoteSetting.vue'
import { MJImageType } from '@/define/enum/mjEnum'
import { isEmpty } from 'lodash'
@@ -64,6 +66,52 @@ async function InitMJSettingData() {
}
} else {
optionStore.MJ_GlobalSetting = JSON.parse(mjRes.data.value)
if (optionStore.MJ_GlobalSetting.mj_apiSetting == null) {
optionStore.MJ_GlobalSetting.mj_apiSetting = {
apiKey: 'key',
id: '6db0d484-2a41-4545-8b26-ed32812965ad',
mjApiUrl: '2b443f53-ba12-42b3-a57c-e4df92685c73',
mjSpeed: 'RELAXED',
useTransfer: false
}
}
if (optionStore.MJ_GlobalSetting.mj_browserSetting == null) {
optionStore.MJ_GlobalSetting.mj_browserSetting = {
channelId: '自己的频道ID111111111',
customUserAgent: true,
id: '4d5d57f2-1d7a-4e0f-b347-a7283e75d64a',
mjBotId: '自己的MJ机器人ID',
nijBotId: '自己的NIJI机器人ID',
serviceId: '自己的服务器IDwwwwww',
token: '自己的令牌11111111111111',
userAgent: '自己的UserAgent111111111111111111111111111',
userAgentCustom: false
}
}
if (optionStore.MJ_GlobalSetting.mj_remoteSimpleSetting == null) {
optionStore.MJ_GlobalSetting.mj_remoteSimpleSetting = {
useTransfer: false
}
}
if (optionStore.MJ_GlobalSetting.mj_simpleSetting == null) {
optionStore.MJ_GlobalSetting.mj_simpleSetting = {
imageModel: '99377cad-c103-4cee-a958-86a104879328',
imageScale: '3e2772f2-041c-49c6-ba13-d0ed120310b8',
imageSuffix: ' --niji 6 --ar 1:1',
requestModel: 'api_mj',
selectRobot: 'niji',
spaceTime: 11,
taskCount: 3,
type: 'api_mj'
}
}
if (optionStore.MJ_GlobalSetting.mj_localRemoteSimpleSetting == null) {
optionStore.MJ_GlobalSetting.mj_localRemoteSimpleSetting = {
baseUrl: 'http://127.0.0.1',
port: '8080',
token: 'admin'
}
}
message.success('加载MJSetting信息成功')
}
await TimeDelay(1000)
@@ -98,7 +146,7 @@ async function SaveMjSetting() {
if (request_model == MJImageType.REMOTE_MJ) {
// 检查是不是有代理账号
let remoteMjRes = await window.setting.GetRemoteMJSettings()
let remoteMjRes = await window.setting.GetRemoteMJSettings('remote')
if (remoteMjRes.code == 0) {
message.error('获取代理MJ配置失败')
return
@@ -123,6 +171,13 @@ async function SaveMjSetting() {
}
}
if (request_model == MJImageType.LOCAL_MJ) {
if (optionStore.MJ_GlobalSetting.mj_localRemoteSimpleSetting.token == null) {
message.error('请检查本地模式代理模式访问令牌是不是为空')
return
}
}
optionStore.MJ_GlobalSetting.mj_simpleSetting.type =
optionStore.MJ_GlobalSetting.mj_simpleSetting.requestModel