V 2.2.10 新增MJ的代理模式

This commit is contained in:
2024-06-24 13:11:19 +08:00
parent 79a1929e79
commit bac97bc41c
102 changed files with 6374 additions and 1172 deletions
+43 -5
View File
@@ -1,5 +1,8 @@
<template>
<n-config-provider :hljs="hljs" :theme="themeData == 'dark' ? darkTheme : null">
<n-config-provider
:hljs="hljs"
:theme="softwareStore.softWare.theme == 'dark' ? darkTheme : null"
>
<n-message-provider>
<n-dialog-provider>
<n-notification-provider>
@@ -21,6 +24,8 @@ import {
darkTheme,
NNotificationProvider
} from 'naive-ui'
import { useSoftwareStore } from '../../stores/software'
hljs.registerLanguage('javascript', javascript)
export default defineComponent({
components: {
@@ -30,20 +35,32 @@ export default defineComponent({
NNotificationProvider
},
setup() {
let themeData = ref('')
let softwareStore = useSoftwareStore()
onMounted(() => {
onMounted(async () => {
window.api.getSettingDafultData(async (value) => {
themeData.value = value.theme
await window.darkMode.toggle(value.theme)
})
let software = await window.setting.GetSoftwareSetting()
if (software.code == 0) {
throw new Error('初始化信息错误: ' + software.message)
}
if (software.data == null) {
throw new Error('初始化信息错误: 未获取到数据')
}
debugger
if (software.data.length == 0) {
throw new Error('初始化信息错误: 未获取到数据')
}
softwareStore.softWare = software.data[0]
await window.darkMode.toggle(softwareStore.softWare.theme)
})
return {
javascript,
hljs,
darkTheme,
themeData
softwareStore
}
}
})
@@ -51,4 +68,25 @@ export default defineComponent({
<style lang="less">
@import './assets/css/styles.less';
/* Customize the scrollbar */
::-webkit-scrollbar {
width: 2px;
height: 4px;
}
/* Track */
::-webkit-scrollbar-track {
background: #f1f1f1;
}
/* Handle */
::-webkit-scrollbar-thumb {
background: #ddd;
}
/* Handle on hover */
::-webkit-scrollbar-thumb:hover {
background: #ccc;
}
</style>
+2
View File
@@ -1,4 +1,6 @@
body {
min-width: 500px;
min-height: 500px;
display: flex;
flex-direction: column;
font-family:
@@ -175,7 +175,6 @@ export default defineComponent({
*/
async function GetVideoFile() {
await window.api.SelectFile(['mp4'], (value) => {
if (value.code == 0) {
message.error(value.message)
return
@@ -193,7 +192,7 @@ export default defineComponent({
message.error('选择分镜的视频地址')
return
}
if (
toRaw(frameValue.value)
.video_path.split('.')
@@ -216,7 +215,10 @@ export default defineComponent({
}
function openExportFolder() {
window.api.OpenFolder("input_crop")
window.system.OpenFolder({
folderPath: 'tmp/input_crop',
baseProject: true
})
}
return {
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,36 @@
<template>
<div ref="artRef"></div>
</template>
<script>
import Artplayer from 'artplayer'
export default {
data() {
return {
instance: null
}
},
props: {
option: {
type: Object,
required: true
}
},
mounted() {
this.instance = new Artplayer({
...this.option,
container: this.$refs.artRef
})
this.$nextTick(() => {
this.$emit('get-instance', this.instance)
})
},
beforeDestroy() {
if (this.instance && this.instance.destroy) {
this.instance.destroy(false)
}
}
}
</script>
+31 -4
View File
@@ -20,7 +20,7 @@
:expand-icon="expandIcon"
/>
</n-layout-sider>
<n-layout-content content-style="padding:30px">
<n-layout-content content-style="padding: 20px 5px 5px 20px; height:100%">
<!-- <Setting></Setting> -->
<router-view></router-view>
</n-layout-content>
@@ -45,7 +45,13 @@ import {
NButton
} from 'naive-ui'
import { BookmarkOutline, CaretDownOutline } from '@vicons/ionicons5'
import {
CaretDownOutline,
PaperPlaneOutline,
SettingsOutline,
DuplicateOutline,
GridOutline
} from '@vicons/ionicons5'
import CheckMachineId from '../Components/CheckMachineId.vue'
import axios from 'axios'
import { DEFINE_STRING } from '../../../../define/define_string.js'
@@ -77,7 +83,12 @@ export default defineComponent({
function renderMenuIcon(option) {
if (option.key === 'sheep-man') return true
if (option.key === 'food') return null
return h(NIcon, null, { default: () => h(BookmarkOutline) })
if (option.key == 'sdoriginal') return h(NIcon, null, { default: () => h(PaperPlaneOutline) })
if (option.key == 'setting') return h(NIcon, null, { default: () => h(SettingsOutline) })
if (option.key == 'reverse_management')
return h(NIcon, null, { default: () => h(GridOutline) })
if (option.key == 'backward_matrix')
return h(NIcon, null, { default: () => h(DuplicateOutline) })
}
onMounted(async () => {
@@ -306,6 +317,21 @@ export default defineComponent({
]
},
// {
// label: () =>
// h(
// RouterLink,
// {
// to: {
// name: 'reverse_management'
// }
// },
// {
// default: () => '一键反推'
// }
// ),
// key: 'reverse_management'
// },
// {
// label: "剪辑",
// key: "clip_options",
// children: [
@@ -386,7 +412,8 @@ export default defineComponent({
{
to: {
name: 'sd_setting'
}
},
class: 'sd_setting'
},
{ default: () => 'SD设置' }
),
@@ -15,66 +15,65 @@
</template>
<script>
import { ref, h, onMounted, defineComponent, toRaw, watch, computed } from "vue";
import { NButton, NCheckbox, NInput, useMessage } from "naive-ui";
import { DEFINE_STRING } from "../../../../../define/define_string";
import { cloneDeep } from "lodash";
import { ref, h, onMounted, defineComponent, toRaw, watch, computed } from 'vue'
import { NButton, NCheckbox, NInput, useMessage } from 'naive-ui'
import { DEFINE_STRING } from '../../../../../define/define_string'
import { cloneDeep } from 'lodash'
export default defineComponent({
components: {
NButton,
NInput,
NCheckbox,
NCheckbox
},
props: ["type", "row", "index", "func"],
props: ['type', 'row', 'index', 'func'],
setup(props) {
let message = useMessage();
let type = ref(props.type);
let row = ref(props.row);
let input_status = ref("default");
let message = useMessage()
let type = ref(props.type)
let row = ref(props.row)
let input_status = ref('default')
// 重新计算命令
watch(
() => props.type,
(newVal) => {
type.value = newVal;
type.value = newVal
},
{ deep: true }
);
)
// 监听数据变化
watch(
() => props.row,
(newVal) => {
row.value = newVal;
row.value = newVal
},
{ deep: true }
);
)
watch(
() => props.row.mj_message,
(newVal) => {
if (newVal && newVal["hasBadPrompt"]) {
input_status.value = "error";
if (newVal && newVal['hasBadPrompt']) {
input_status.value = 'error'
}
},
{ deep: true }
);
)
onMounted(async () => {
if (row.value["mj_message"]?.hasBadPrompt) {
input_status.value = "error";
if (row.value['mj_message']?.hasBadPrompt) {
input_status.value = 'error'
}
});
})
async function onUpdateChecked(v) {
row.adetailer = v;
row.value.adetailer = v
}
return {
type,
row,
onUpdateChecked,
};
},
});
onUpdateChecked
}
}
})
</script>
@@ -28,10 +28,11 @@
</template>
<script>
import { h, defineComponent, onMounted, ref, toRaw, watch } from 'vue'
import { h, defineComponent, onMounted, ref, toRaw, watch, onUnmounted } from 'vue'
import { NButton, NDataTable, useMessage, NInput, NImage, useDialog } from 'naive-ui'
import { v4 as uuidv4 } from 'uuid'
import EditWord from './EditWord.vue'
import { checkStringValueDeleteSuffix } from '../../../../../main/generalTools'
const buttonArr = [
{
title: '下对齐',
@@ -39,6 +40,7 @@ const buttonArr = [
color: '#8a2be0'
}
]
import InputDialogContent from './InputDialogContent.vue'
export default defineComponent({
components: {
@@ -53,9 +55,10 @@ export default defineComponent({
let maxHeight = props.height - 80
let data = ref(props.initData)
const message = useMessage()
let selectKey = ref([])
let dialog = useDialog()
let selectKey = ref([])
let editWordRef = ref(null)
let wenkeRef = ref(null)
const createColumns = ({ AlignNextWord }) => {
return [
@@ -158,18 +161,115 @@ export default defineComponent({
// 设置窗体的高度
function setHeight() {
let div = document.getElementById('import_word_and_srt')
div.style.height = hh + 'px'
}
onMounted(async () => {
setHeight()
// 监听 ctrl + alt + w 键盘的按键事件
window.addEventListener('keydown', ImportWenKeSrt)
})
onUnmounted(() => {
window.removeEventListener('keydown', ImportWenKeSrt)
})
/**
* 导入文刻软件里面的srt
*/
async function ImportWenKeSrt(e) {
if (!(e.ctrlKey && e.altKey && e.key == 'k')) {
return
}
let dialogWidth = 400
let dialogHeight = 150
dialog.create({
name: 'importWenkeWord',
title: '导入外部对齐文件',
showIcon: false,
closeOnEsc: false,
content: () =>
h(InputDialogContent, {
ref: wenkeRef,
initData: null,
placeholder: '请导入外部对齐文件'
}),
style: `width : ${dialogWidth}px; min-height : ${dialogHeight}px`,
maskClosable: false,
onClose: async () => {
debugger
console.log(wenkeRef.value.word)
let word = wenkeRef.value.data
if (word == null || word == '') {
message.error('数据为空')
return
}
word = JSON.parse(word)
// 将文案数据写入到本地
data.value = []
let word_arr = word.rows
let lastId = ''
let end_word = []
for (let i = 0; i < word_arr.length; i++) {
const element = word_arr[i]
// 判断下面的text是不是存在,存在的话,获取数据然后记录事件
let row_text = ''
let start_time = 0
let end_time = 0
let subValue = []
if (element.texts) {
for (let j = 0; j < element.texts.length; j++) {
const text = element.texts[j]
row_text += text.text + ','
if (j == 0) {
start_time = text.start
}
if (j == element.texts.length - 1) {
end_time = text.start + text.duration
}
subValue.push({
id: uuidv4(),
srt_value: text.text,
start_time: text.start / 1000,
end_time: text.start / 1000 + text.duration / 1000
})
}
}
let id = uuidv4()
lastId = id
data.value.push({
no: i + 1,
id: id,
lastId: lastId,
word: checkStringValueDeleteSuffix(row_text, ','),
after_gpt: checkStringValueDeleteSuffix(row_text, ','),
start_time: start_time / 1000,
end_time: end_time / 1000,
timeLimit: `${start_time / 1000} -- ${end_time / 1000}`,
subValue: subValue
})
end_word.push(checkStringValueDeleteSuffix(row_text, ','))
}
// 将文案数据写入到本地
let local_word = end_word.filter((item) => item != '' && item != null)
await window.api.saveWordTxt(toRaw(local_word), (value) => {
if (value.code == 0) {
message.error('文案写入失败' + value.message)
return
}
})
return true
}
})
}
/**
* 重新计算指定索引值的时间
* @param {data value 值的索引} index
* @param {int} index
*/
function modifyTime(index) {
let s_v = data.value[index].subValue
@@ -423,7 +523,6 @@ export default defineComponent({
})
return
} else {
// 先保存单个文件(然后在config文件中指向对应的文件)
await window.api.OriginalAddWebuiJson(JSON.stringify(data.value), async (value) => {
if (value.code == 0) {
@@ -466,7 +565,6 @@ export default defineComponent({
})
await window.api.ImportSrtAndGetTime([toRaw(data.value), srt_path], (value) => {
if (value.code == 0) {
message.error(value.message)
return
@@ -552,7 +650,8 @@ export default defineComponent({
SaveCopywritingInformation,
OpenOneDialog,
maxHeight,
hh
hh,
wenkeRef
}
}
})
@@ -85,44 +85,33 @@
size="small"
placeholder="请选择"
:options="request_model_options"
v-model:value="mjSetting.request_model"
v-model:value="mjSetting.requestModel"
style="width: 120px"
>
</n-select>
</div>
<div style="margin-left: 10px; display: flex; flex-wrap: wrap; width: 80px">
<div style="margin-bottom: 3px">出图机器人</div>
<n-select
size="small"
placeholder="请选择"
:options="select_robot_options"
v-model:value="mjSetting.select_robot"
style="width: 80px"
>
</n-select>
</div>
<div style="margin-left: 10px; display: flex; flex-wrap: wrap; width: 100px">
<div style="margin-bottom: 3px">出图速度模式</div>
<n-select
size="small"
placeholder="请选择"
:options="mj_speed_options"
v-model:value="mjSetting.mj_speed"
style="width: 100px"
>
</n-select>
</div>
<div style="margin-left: 10px; display: flex; flex-wrap: wrap; width: 80px">
<div style="margin-bottom: 3px">MJ并发数量</div>
<div style="margin-bottom: 3px">MJ并发</div>
<n-input-number
size="small"
style="width: 80px"
v-model:value="mjSetting.task_count"
v-model:value="mjSetting.taskCount"
:show-button="false"
:min="1"
:max="10"
:max="20"
/>
</div>
<div style="margin-left: 10px; display: flex; flex-wrap: wrap; width: 80px">
<div style="margin-bottom: 3px">间隔时间</div>
<n-input-number
size="small"
style="width: 80px"
v-model:value="mjSetting.spaceTime"
:show-button="false"
:min="1"
:max="30"
/>
</div>
@@ -198,13 +187,11 @@ export default defineComponent({
let character_select_model = ref(window.config.character_select_model)
let character_select_model_options = ref([])
let mjSetting = ref({
select_robot: null,
task_count: 1,
request_model: null,
mj_speed: 'relaxed'
selectRobot: null,
taskCount: 3,
spaceTime: 1
})
let request_model_options = ref([])
let select_robot_options = ref([])
let mj_speed_options = ref([])
/**
@@ -248,21 +235,19 @@ export default defineComponent({
* 初始化MJ的option
*/
async function InitMjOptions() {
// 获取当前mj配置信息
await window.api.GetDefineConfigJsonByProperty(
JSON.stringify(['img_base', 'mj_config', false, null]),
(value) => {
console.log(value)
if (value.code == 0) {
message.error(value.message)
return
}
// 判断是不是有数据
if (value.data) {
mjSetting.value = value.data
}
}
)
// 获取当前mj配置信息,加载基础信息
let res = await window.setting.GetMjSetting()
if (res.code == 0) {
message.error(res.message)
return
}
if (res.data.length <= 0) {
message.error('当前没有MJ配置信息,请先配置MJ信息')
return
}
mjSetting.value = Object.assign(mjSetting.value, res.data[0])
await window.mj.GetMJGenerateCategory((value) => {
if (value.code == 0) {
@@ -274,16 +259,6 @@ export default defineComponent({
mjSetting.value.request_model = request_model_options.value[0].value
}
})
select_robot_options.value = [
{
label: 'MJ',
value: 'mj'
},
{
label: 'NIJI',
value: 'niji'
}
]
mj_speed_options.value = [
{
@@ -348,17 +323,11 @@ export default defineComponent({
}
})
// 保存MJ
await window.api.SaveDefineConfigJsonByProperty(
JSON.stringify(['img_base', 'mj_config', toRaw(mjSetting.value), false]),
(value) => {
if (value.code == 0) {
message.error(value.message)
return
}
}
)
// 保存MJ的基础设
let saveMjRes = await window.setting.UpdateMJSetting(toRaw(mjSetting.value))
if (saveMjRes.code == 0) {
throw new Error(saveMjRes.message)
}
message.success('保存成功')
} catch (error) {
@@ -425,7 +394,6 @@ export default defineComponent({
bad_prompt_ref,
mjSetting,
request_model_options,
select_robot_options,
mj_speed_options
}
}
@@ -563,7 +563,7 @@ export default defineComponent({
// 计算当前程序界面的高度,减去上下的高度,设置maxHegiht
async function getMaxHeight() {
let height = window.innerHeight
maxHeight.value = height - 150
maxHeight.value = height - 120
}
// 监听程序界面的高度变化
@@ -15,11 +15,12 @@
<script>
import { ref, h, onMounted, defineComponent, onUnmounted, toRaw } from 'vue'
import { NImage, useMessage } from 'naive-ui'
import { NImage, useMessage, useDialog } from 'naive-ui'
import { DEFINE_STRING } from '../../../../define/define_string'
import MenuButton from './MenuButton.vue'
import DataTable from './DataTable.vue'
import { usePromptStore } from '../../../../stores/prompt'
import InputDialogContent from './Components/InputDialogContent.vue'
export default defineComponent({
components: {
@@ -28,6 +29,7 @@ export default defineComponent({
MenuButton
},
setup() {
let dialog = useDialog()
let promptStore = usePromptStore()
let message = useMessage()
let data = ref([])
@@ -35,9 +37,9 @@ export default defineComponent({
let AnalyzeCharacter = ref('')
let TagTreeData = ref([])
let promptError = true
let wenkeRef = ref(null)
async function InitData() {
// 加载
// 初始化加载项目下面的分镜好的文案
// 并判断是不是有洗稿后的文件。一并加载
@@ -125,7 +127,6 @@ export default defineComponent({
* 初始化数据
*/
async function InItPromptSort() {
await window.pmpt.GetPromptSort((value) => {
if (value.code == 0) {
message.error(value.message)
@@ -135,10 +136,66 @@ export default defineComponent({
})
}
// 导入提示词
async function ImportWenKePrompt(e) {
if (!(e.ctrlKey && e.altKey && e.key == 'm')) {
return
}
// 弹窗选择文件
window.api.SelectFile(['txt'], async (value) => {
if (value.code == 0) {
message.error(value.message)
return
}
debugger
console.log(value.value)
// 拿到提示词文件地址,然后还是获取
await window.pmpt.OpenPromptFileTxt(value.value, (res) => {
debugger
console.log(res)
if (res.code == 0) {
message.error(res.message)
return
}
// 修改数据
// 判断获取的数据是不是小于当前的data的行
if (res.data.length > data.value.length) {
dialog.warning({
title: '提示',
content: '导入的数据行数大于当前的数据行数,多余的数据会被删除,是否继续导入?',
positiveText: '继续',
negativeText: '取消',
onPositiveClick: async () => {
debugger
// 开始导入
for (let i = 0; i < data.value.length && i < res.data.length; i++) {
const element = res.data[i]
// 开始修改
data.value[i].gpt_prompt = element
}
}
})
} else {
// 开始导入
for (let i = 0; i < data.value.length && i < res.data.length; i++) {
const element = res.data[i]
// 开始修改
data.value[i].gpt_prompt = element
}
}
})
})
}
onMounted(async () => {
await InitData()
await InitTags()
await InItPromptSort()
window.addEventListener('keydown', ImportWenKePrompt)
})
onUnmounted(() => {
window.removeEventListener('keydown', ImportWenKePrompt)
})
return {
@@ -147,7 +204,8 @@ export default defineComponent({
TagTreeData,
InitData,
InitTags,
tags
tags,
wenkeRef
}
}
})
@@ -324,7 +324,7 @@ export default defineComponent({
)
} else if (value == 'resetPrompt') {
// 重置提示词
console.log(data)
await ResetPrompt()
} else if (value == 'resetImage') {
@@ -349,7 +349,6 @@ export default defineComponent({
auto_save,
railStyle,
AutoSaveUpdate: (value) => {
auto_save.value = value
window.config.auto_save = value
},
@@ -0,0 +1,263 @@
<template>
<div style="margin: 30px 30px 30px 0">
<n-form
ref="bookRef"
:model="data"
:rules="rules"
label-placement="left"
label-width="auto"
require-mark-placement="right-hanging"
>
<n-form-item label="书名" path="name">
<n-input v-model:value="data.name" placeholder="请输入书名" />
</n-form-item>
<n-form-item label="视频文件" path="oldVideoPath">
<n-input
disabled="true"
v-model:value="data.oldVideoPath"
placeholder="请选择反推的视频文件"
clearable
>
<template #suffix>
<n-button @click="ClearInputData('oldVideoPath')" text style="font-size: 20px">
<n-icon>
<CloseSharp />
</n-icon>
</n-button>
</template>
</n-input>
<n-button type="info" @click="SelectMP4File('oldVideoPath')" style="margin-left: 10px"
>选择视频</n-button
>
</n-form-item>
<n-form-item label="小说类型" path="type">
<n-select
v-model:value="data.type"
:disabled="reverseManageStore.selectBook.id != null"
:options="reverseManageStore.bookType"
style="width: 200px"
>
</n-select>
</n-form-item>
<n-form-item label="配音地址" path="audioPath">
<n-input
v-model:value="data.audioPath"
disabled="true"
placeholder="没有选择的话则使用原视频的"
>
<template #suffix>
<n-button @click="ClearInputData('audioPath')" text style="font-size: 20px">
<n-icon>
<CloseSharp />
</n-icon>
</n-button> </template
></n-input>
<n-button type="info" @click="SelectMP4File('audioPath')" style="margin-left: 10px"
>选择配音</n-button
>
</n-form-item>
<n-form-item label="SRT地址" path="srtPath">
<n-input
v-model:value="data.srtPath"
disabled="true"
placeholder="没有选择的话则使用原视频的"
>
<template #suffix>
<n-button @click="ClearInputData('srtPath')" text style="font-size: 20px">
<n-icon>
<CloseSharp />
</n-icon>
</n-button> </template
></n-input>
<n-button type="info" @click="SelectMP4File('srtPath')" style="margin-left: 10px"
>选择SRT</n-button
>
</n-form-item>
<n-form-item label="小说项目文件夹" path="bookFolderPath">
<n-input
v-model:value="data.bookFolderPath"
disabled="true"
placeholder="不用选择,添加小说自动生成"
>
</n-input>
<n-button type="info" @click="OpenFolder('bookFolderPath')" style="margin-left: 10px"
>打开</n-button
>
</n-form-item>
<n-form-item label="图片输出文件夹" path="imageFolder">
<n-input
v-model:value="data.imageFolder"
disabled="true"
placeholder="不用选择,添加小说自动生成"
>
</n-input>
<n-button type="info" @click="OpenFolder('imageFolder')" style="margin-left: 10px"
>打开</n-button
>
</n-form-item>
<div style="margin-left: 10px; display: flex; justify-content: flex-end">
<n-button type="success" @click="AddOrModifyBook">添加</n-button>
</div>
</n-form>
</div>
</template>
<script>
import { ref, onMounted, defineComponent, onUnmounted, toRaw, watch } from 'vue'
import { useMessage, NButton, NForm, NFormItem, NInput, NSelect, NIcon } from 'naive-ui'
import { useReverseManageStore } from '../../../../../stores/reverseManage.js'
import { CloseSharp } from '@vicons/ionicons5'
import { cloneDeep } from 'lodash'
export default defineComponent({
components: {
NButton,
NForm,
NFormItem,
NInput,
NSelect,
NIcon,
CloseSharp
},
setup() {
let message = useMessage()
let reverseManageStore = useReverseManageStore()
let bookRef = ref(null)
let data = ref(cloneDeep(reverseManageStore.selectBook))
onMounted(async () => {
// 初始化小说类型
let res = await reverseManageStore.SetBookType()
if (res.code == 0) {
message.error(res.message)
return
}
})
/**
* 选择 MP4 视频文件
*/
async function SelectMP4File(propertyName) {
let ext = ['mp4']
if (propertyName == 'audioPath') {
ext = ['mp3', 'wav']
} else if (propertyName == 'srtPath') {
ext = ['srt']
}
// 选择MP4文件夹
await window.api.SelectFile(ext, (value) => {
debugger
if (value.code == 0) {
message.error(value.message)
return
}
if (value.value == null) {
message.error('没有选中的数据')
return
}
if (propertyName == 'oldVideoPath') {
data.value.oldVideoPath = value.value
} else if (propertyName == 'audioPath') {
data.value.UpdateSelectBook = value.value
} else if (propertyName == 'srtPath') {
data.value.srtPath = value.value
} else {
message.error('没有找到对应的属性')
}
})
}
let ruleObj = (errorMessage) => {
return [
{
required: true,
validator(rule, value) {
if (value == null || value == '') return new Error(errorMessage)
return true
},
trigger: ['input', 'blur', 'change']
}
]
}
let rules = {
name: ruleObj('书名必填'),
oldVideoPath: ruleObj('反推的视频文件地址必填'),
type: ruleObj('小说类型必填')
}
/**
* 添加或者是修改数据(通过ID判断)
*/
async function AddOrModifyBook(e) {
// 校验数据
e.preventDefault()
bookRef.value?.validate(async (errors) => {
if (errors) {
message.error('请检查必填字段')
return
}
debugger
let res = await reverseManageStore.SaveSelectBook(toRaw(data.value))
// 判断当前的数据是不是有ID
if (res.code == 0) {
message.error(res.message)
return
}
message.success('添加/修改成功')
data.value = reverseManageStore.selectBook
})
}
//清空MP4路劲信息
function ClearInputData(propertyName) {
if (propertyName == 'oldVideoPath') {
reverseManageStore.UpdateSelectBook({ oldVideoPath: null })
} else if (propertyName == 'audioPath') {
reverseManageStore.UpdateSelectBook({ audioPath: null })
} else if (propertyName == 'srtPath') {
reverseManageStore.UpdateSelectBook({ srtPath: null })
} else {
message.error('没有找到对应的属性')
}
}
/**
* 打开指定的文件夹
* @param param
*/
async function OpenFolder(param) {
let res = null
debugger
if (param == 'imageFolder') {
res = await window.system.OpenFolder({
folderPath: data.value.imageFolder,
baseProject: false
})
} else if (param == 'bookFolderPath') {
res = await window.system.OpenFolder({
folderPath: data.value.bookFolderPath,
baseProject: false
})
} else {
message.error('未知的参数')
return
}
if (res.code == 0) {
message.error(res.message)
return
}
}
return {
reverseManageStore,
rules,
ClearInputData,
SelectMP4File,
AddOrModifyBook,
bookRef,
OpenFolder,
data
}
}
})
</script>
@@ -0,0 +1,89 @@
<template>
<n-button
:size="softwareStore.softWare.reverse_data_table_size"
strong
secondary
type="primary"
@click="EditBook"
>编辑</n-button
>
<n-button
:size="softwareStore.softWare.reverse_data_table_size"
strong
secondary
style="margin-left: 5px"
type="info"
>任务</n-button
>
<n-button
:size="softwareStore.softWare.reverse_data_table_size"
strong
secondary
style="margin-left: 5px"
type="warning"
@click="EditBook"
>重置</n-button
>
<n-button
:size="softwareStore.softWare.reverse_data_table_size"
style="margin-left: 5px"
strong
secondary
type="error"
>删除
</n-button>
</template>
<script>
import { ref, onMounted, defineComponent, h, onUnmounted, toRaw, watch } from 'vue'
import { useMessage, NButton, useDialog } from 'naive-ui'
import { useReverseManageStore } from '../../../../../stores/reverseManage'
import { useSoftwareStore } from '../../../../../stores/software'
import { BookType } from '../../../../../define/enum/bookEnum'
import AddBook from './AddBook.vue'
export default defineComponent({
components: {
NButton
},
props: ['book'],
setup(props) {
let message = useMessage()
let dialog = useDialog()
let book = ref(props.book)
let reverseManageStore = useReverseManageStore()
let softwareStore = useSoftwareStore()
onMounted(async () => {})
/**
* 编辑小说数据
*/
async function EditBook(e) {
e.stopPropagation()
// 修改选中的数据
debugger
reverseManageStore.SetSelectBook(toRaw(book.value))
// 一个弹窗添加数据
let dialogWidth = 600
// ImportWordAndSrt
dialog.create({
showIcon: false,
closeOnEsc: false,
title: '新增小说',
content: () => h(AddBook),
style: `width : ${dialogWidth}px;`,
maskClosable: false
})
}
return {
book,
reverseManageStore,
softwareStore,
EditBook
}
}
})
</script>
@@ -0,0 +1,146 @@
<template>
<div style="display: flex; justify-content: space-between">
<n-button :render-icon="renderIcon" type="info" @click="AddBookDialog">新增</n-button>
<div style="display: flex; justify-content: flex-end; margin-right: 10px; align-items: center">
<n-popover trigger="hover">
<template #trigger>
<n-switch
v-model:value="softwareStore.softWare.reverse_show_book_striped"
@update:value="DataTableStripedUpdate"
/>
</template>
<span>显示斑马纹</span>
</n-popover>
<n-popover trigger="hover">
<template #trigger>
<n-button text style="font-size: 20px; margin-left: 10px">
<n-icon>
<ReloadSharp />
</n-icon>
</n-button>
</template>
<span>刷新数据</span>
</n-popover>
<n-dropdown trigger="click" :options="softwareStore.componentSize" @select="SelectDropdown">
<n-button text style="font-size: 20px; margin-left: 10px; font-weight: bold">
Size</n-button
>
</n-dropdown>
<n-button text style="margin-left: 10px; font-size: 20px" @click="SwitchShowTemp">
<n-icon>
<SwapHorizontalSharp />
</n-icon>
</n-button>
</div>
</div>
</template>
<script>
import { ref, onMounted, defineComponent, onUnmounted, h, toRaw, computed } from 'vue'
import { useMessage, NButton, NIcon, useDialog, NPopover, NSwitch, NDropdown } from 'naive-ui'
import { AddSharp, ReloadSharp, ResizeSharp, SwapHorizontalSharp } from '@vicons/ionicons5'
import AddBook from './AddBook.vue'
import { useSoftwareStore } from '../../../../../stores/software'
import { useReverseManageStore } from '../../../../../stores/reverseManage.js'
import { BookType } from '../../../../../define/enum/bookEnum'
export default defineComponent({
components: {
NButton,
AddSharp,
NIcon,
ReloadSharp,
NPopover,
NSwitch,
NDropdown,
ResizeSharp,
SwapHorizontalSharp
},
setup() {
let message = useMessage()
let dialog = useDialog()
let softwareStore = useSoftwareStore()
let reverseManageStore = useReverseManageStore()
let book = ref(null)
onMounted(async () => {
// 初始化一下吧
await softwareStore.GetComponentSize()
})
async function SwitchShowTemp() {
// 判断当前显示的状态
// 显示加载1秒
softwareStore.softWare.reverse_display_show = !softwareStore.softWare.reverse_display_show
}
// 新增新增小说
async function AddBookDialog() {
// 将选中数据清空
reverseManageStore.SetSelectBook({
name: null,
id: null,
type: BookType.MJ_REVERSE
})
// 一个弹窗添加数据
let dialogWidth = 600
// ImportWordAndSrt
dialog.create({
showIcon: false,
closeOnEsc: false,
title: '新增小说',
content: () => h(AddBook),
style: `width : ${dialogWidth}px;`,
maskClosable: false
})
}
/**
* 修改设置
*/
async function DataTableStripedUpdate() {
// 修改数据
debugger
// 直接提交修改
let res = await softwareStore.SaveSoftware()
console.log(res)
if (res.code == 0) {
message.error(res.message)
return
}
}
// 选择下拉菜单
async function SelectDropdown(key) {
debugger
console.log(key)
softwareStore.softWare.reverse_data_table_size = key
// 直接提交修改
let res = await softwareStore.SaveSoftware()
if (res.code == 0) {
message.error(res.message)
return
}
message.success('切换成功')
}
return {
SwitchShowTemp,
renderIcon() {
return h(NIcon, null, {
default: () => h(AddSharp, { size: '40', color: 'white' }, {})
})
},
AddBookDialog,
book,
reverseManageStore,
softwareStore,
DataTableStripedUpdate,
SelectDropdown
}
}
})
</script>
@@ -0,0 +1,60 @@
<template>
<div>
<n-button strong secondary @click="RetuenMain"> 返回 </n-button>
<n-dropdown trigger="hover" :options="AutoOptions" @select="SelectAutoAction">
<n-button color="#ee7959" @click="AutoAction" style="margin-left: 5px"> 自动开始 </n-button>
</n-dropdown>
</div>
</template>
<script>
import { ref, onMounted, defineComponent, onUnmounted, toRaw, watch } from 'vue'
import { useMessage, NButton, NCheckbox, NDropdown } from 'naive-ui'
import { useRouter } from 'vue-router'
import { useReverseManageStore } from '../../../../../stores/reverseManage'
export default defineComponent({
components: {
NButton,
NCheckbox,
NDropdown
},
setup() {
let router = useRouter()
let reverseManageStore = useReverseManageStore()
// 获取当前这个界面的数据
onMounted(async () => {})
// 返回主页
function RetuenMain() {
router.push('/reverse_management')
}
// 自动开始
async function AutoAction() {
// 开始自动执行。先分镜,后面在添加任务中
let res_frame = await window.book.GetFrameData(reverseManageStore.selectBook.id)
}
// 选择自动开始的操作(停止或者是继续)
async function SelectAutoAction() {}
return {
RetuenMain,
AutoAction,
reverseManageStore,
AutoOptions: [
{
label: '停止任务',
value: 'auto_stop'
},
{
label: '继续任务',
value: 'auto_continue'
}
]
}
}
})
</script>
@@ -0,0 +1,18 @@
<template>
<div>ManageBookReverseTable</div>
</template>
<script>
import { ref, onMounted, defineComponent, onUnmounted, toRaw, watch } from 'vue'
import { useMessage } from 'naive-ui'
export default defineComponent({
components: {},
setup() {
onMounted(async () => {})
return {}
}
})
</script>
@@ -0,0 +1,87 @@
<template>
<div class="artplayer-app" style="height: 100%">
<Artplayer @get-instance="getInstance" :option="option" :style="palyarStyle" />
<n-log
style="height: 60%; background-color: #f8f8f8"
ref="logInst"
:log="logger"
:loading="loading"
trim
/>
</div>
</template>
<script>
import { ref, onMounted, defineComponent, onUnmounted, toRaw, nextTick, watchEffect } from 'vue'
import { useMessage, NLog } from 'naive-ui'
import Artplayer from '../../Components/Artplayer.vue'
import { useReverseManageStore } from '../../../../../stores/reverseManage'
import { DEFINE_STRING } from '../../../../../define/define_string'
export default defineComponent({
components: { Artplayer, NLog },
setup() {
let message = useMessage()
let reverseManageStore = useReverseManageStore()
let option = {
container: '.artplayer-app',
id: reverseManageStore.selectBook.id,
url: reverseManageStore.selectBook.oldVideoPath,
playbackRate: true,
aspectRatio: true,
mutex: true,
setting: true,
hotkey: true,
autoSize: true,
fullscreen: true
}
let palyarStyle = {
width: '300px',
height: '300px',
margin: '0 auto'
}
let logger = ref('')
const logInst = ref(null)
let loading = ref(false)
onMounted(async () => {
// 监听返回的日志数据
window.api.setEventListen([DEFINE_STRING.SYSTEM.RETURN_LOGGER], (value) => {
debugger
if (value.code == 0) {
message.error('添加日志输出失败,但是不影响使用')
logger.value += value.message + '\n'
return
}
let temp_logger = value.data
// 将成功的日志数据添加到日志组件
let log = `[${temp_logger.type}] [${temp_logger.date.toLocaleString()}] [${
temp_logger.status
}] [${temp_logger.content}]`
logger.value += log + '\n'
})
// 监听,将新添加的日志滚动在最下面
watchEffect(() => {
if (logger.value) {
nextTick(() => {
logInst.value?.scrollTo({ position: 'bottom', silent: true })
})
}
})
})
return {
reverseManageStore,
option,
getInstance(art) {
// console.info(art)
},
palyarStyle,
logger,
logInst,
loading
}
}
})
</script>
@@ -0,0 +1,207 @@
<template>
<div style="margin-bottom: 10px">
<ManageBookButton />
</div>
<div style="margin-right: 10px">
<n-data-table
:columns="columns"
:size="softwareStore.softWare.reverse_data_table_size"
:data="data"
:pagination="pagination"
:bordered="false"
:remote="true"
:striped="softwareStore.softWare.reverse_show_book_striped"
:scroll-x="1000"
:row-props="rowProps"
:max-height="maxHeight"
/>
</div>
</template>
<script>
import { ref, onMounted, defineComponent, onUnmounted, toRaw, reactive, computed, h } from 'vue'
import { useMessage, NButton, NDataTable, NTag, NEllipsis } from 'naive-ui'
import ManageBookButton from './Components/ManageBookButton.vue'
import { useSoftwareStore } from '../../../../stores/software'
import { useReverseManageStore } from '../../../../stores/reverseManage.js'
import { BookType } from '../../../../define/enum/bookEnum'
import BookListAction from './Components/BookListAction.vue'
import { useRouter } from 'vue-router'
export default defineComponent({
components: {
NButton,
ManageBookButton,
NDataTable,
NEllipsis
},
setup() {
let message = useMessage()
let softwareStore = useSoftwareStore()
let reverseManageStore = useReverseManageStore()
let data = computed(() => reverseManageStore.GetBookData())
const router = useRouter()
let maxHeight = ref(0)
// 分页设置
const paginationReactive = (() => {
return reactive({
page: 1,
pageSize: 10,
showSizePicker: true,
pageSizes: [10, 20, 50, 100],
onChange: async (page) => {
// 加载数据。切换,重新架子啊数据
paginationReactive.page = page
await GetBookByCondition()
},
onUpdatePageSize: async (pageSize) => {
paginationReactive.pageSize = pageSize
paginationReactive.page = 1
await GetBookByCondition()
}
})
})()
let pagination = computed(() => {
return paginationReactive
})
async function GetBookByCondition() {
try {
debugger
let res = await reverseManageStore.GetBookDataFromDB({
page: paginationReactive.page,
pageSize: paginationReactive.pageSize
})
if (res.code == 0) {
message.error(res.message)
return
}
let res_count = res.data.book_length / pagination.value.pageSize
if (!Number.isInteger(res_count)) {
res_count = Math.ceil(res_count)
}
pagination.value.pageCount = res_count
// 开始获取批次任务
let bookTask = await reverseManageStore.GetBookTaskDataFromDB({
bookId: reverseManageStore.selectBook.id
})
if (bookTask.code == 0) {
message.error(bookTask.message)
return
}
} catch (error) {
message.error('获取小说数据失败')
}
}
async function InitData() {
try {
// 初始化数据
debugger
await GetBookByCondition()
} catch (error) {
message.error(error.message)
}
}
onMounted(async () => {
await InitData()
getMaxHeight()
// 监听窗口的大小变化
window.addEventListener('resize', getMaxHeight)
})
// 计算当前程序界面的高度,减去上下的高度,设置maxHegiht
function getMaxHeight() {
let height = window.innerHeight
maxHeight.value = height - 180
}
const createColumns = () => {
return [
{
title: 'No.',
key: 'no',
width: 50
},
{
title: '小说名',
key: 'name',
render: (row) => {
return h(
'div',
{
style:
'overflow: hidden; max-width : 100px; white-space: nowrap; text-overflow: ellipsis;'
},
{ default: () => row.name }
)
},
width: 100
},
{
title: '类型',
key: 'type',
width: 80,
render: (row) => {
return h(
NTag,
{ type: 'success', size: softwareStore.softWare.reverse_data_table_size },
{
default: () => getTyleLabel(row.type)
}
)
}
},
{
title: '原视频',
key: 'oldVideoPath'
},
{
title: '操作',
key: 'action',
width: 310,
fixed: 'right',
render: (row) => {
return h(BookListAction, { book: row })
}
}
]
}
function getTyleLabel(value) {
if (value == BookType.MJ_REVERSE) {
return 'MJ反推'
} else if (value == BookType.SD_REVERSE) {
return 'SD反推'
} else if (value == BookType.ORIGINAL) {
return '原创'
} else {
return '未知'
}
}
return {
softwareStore,
reverseManageStore,
data,
pagination,
maxHeight,
columns: createColumns(),
rowProps: (row) => {
return {
style: 'cursor: pointer;',
onClick: () => {
debugger
message.info(row.id)
reverseManageStore.selectBook = row
router.push({ name: 'manage_book', params: { id: row.id } })
}
}
}
}
}
})
</script>
@@ -0,0 +1,37 @@
<template>
<div style="height: 100%; display: flex; width: 100%; overflow: auto">
<div v-if="true" class="left_container" style="flex: 10; min-width: 600px">
<ManageBookDetailButton />
<ManageBookReverseTable style="margin-top: 10px" />
</div>
<div >
<n-divider vertical style="height: 100%"></n-divider>
</div>
<div class="right_container" style="flex: 3; min-width: 250px">
<ManageBookShowLogger />
</div>
</div>
</template>
<script>
import { ref, onMounted, defineComponent, onUnmounted, toRaw, watch } from 'vue'
import { useMessage, NDivider } from 'naive-ui'
import ManageBookDetailButton from './Components/ManageBookDetailButton.vue'
import ManageBookReverseTable from './Components/ManageBookReverseTable.vue'
import ManageBookShowLogger from './Components/ManageBookShowLogger.vue'
export default defineComponent({
components: {
ManageBookDetailButton,
ManageBookReverseTable,
ManageBookShowLogger,
NDivider
},
setup() {
onMounted(async () => {})
return {}
}
})
</script>
@@ -0,0 +1,21 @@
<template>
<div>按钮</div>
</template>
<script>
import { ref, onMounted, defineComponent, onUnmounted, toRaw, watch } from 'vue'
import { useMessage, NButton, NDataTable } from 'naive-ui'
export default defineComponent({
components: {
NButton,
NDataTable
},
setup() {
onMounted(async () => {})
return {}
}
})
</script>
@@ -0,0 +1,48 @@
<template>
<div style="height: 100%">
<ManageBook style="height: 100%" v-if="softwareStore.softWare.reverse_display_show" />
<n-split v-else direction="horizontal" :min="0.4" :max="0.8" :default-size="0.6" height="100%">
<template #1> <ManageBook style="height: 100%" /> </template>
<template #2>
<ManageBookTask style="height: 100%" />
</template>
</n-split>
<n-float-button :right="30" :bottom="30" shape="circle">
<n-badge :value="100" :max="99" :offset="[6, -8]">
<n-icon :size="large">
<Layers />
</n-icon>
</n-badge>
</n-float-button>
</div>
</template>
<script>
import { ref, onMounted, defineComponent, onUnmounted, toRaw, watch, onBeforeMount } from 'vue'
import { useMessage, NSplit, NSpin, NFloatButton, NIcon, NBadge } from 'naive-ui'
import ManageBook from './ManageBook.vue'
import ManageBookTask from './ManageBookTask.vue'
import { useSoftwareStore } from '../../../../stores/software'
import { useReverseManageStore } from '../../../../stores/reverseManage.js'
import { Layers } from '@vicons/ionicons5'
export default defineComponent({
components: { NSplit, ManageBook, ManageBookTask, NSpin, NFloatButton, NIcon, Layers, NBadge },
setup() {
let message = useMessage()
let isShowTask = ref(false)
let softwareStore = useSoftwareStore()
let reverseManageStore = useReverseManageStore()
onMounted(() => {})
return {
isShowTask,
softwareStore,
reverseManageStore
}
}
})
</script>
+484 -332
View File
@@ -1,153 +1,271 @@
<template>
<n-button type="info" round @click="OpenDiscordWindow">打开登录MJ</n-button>
<n-button type="info" round @click="GetChannelRobots" style="margin-left: 10px"
>获取频道机器人</n-button
>
<n-button type="info" round @click="SaveMjSetting" style="margin-left: 10px">保存MJ配置</n-button>
<n-divider />
<n-form ref="formRef" label-placement="top" :model="mjSetting" :rules="rules">
<div style="display: flex">
<n-form-item label="服务器ID" style="width: 400px" path="serviceID">
<n-input v-model:value="mjSetting.serviceID" placeholder="登录MJ后切换服务器自动获取" />
</n-form-item>
<n-form-item label="频道ID" style="width: 400px; margin-left: 10px" path="channelID">
<n-input v-model:value="mjSetting.channelID" placeholder="登录MJ后切换频道自动获取" />
</n-form-item>
</div>
<!-- <div style="display: flex">
<n-form-item label="MJ机器ID" path="mj.botId">
<n-input v-model:value="mjSetting.mj.botId" placeholder="MJ机器ID" />
</n-form-item>
<n-form-item label="MJ命令ID" style="margin-left: 10px" path="mj.commandId">
<n-input v-model:value="mjSetting.mj.commandId" placeholder="MJ命令ID" />
</n-form-item>
<n-form-item label="MJ命令名称" style="margin-left: 10px" path="mj.commandName">
<n-input v-model:value="mjSetting.mj.commandName" placeholder="MJ命令名称" />
</n-form-item>
<n-form-item label="MJ版本ID" style="margin-left: 10px" path="mj.versionId">
<n-input v-model:value="mjSetting.mj.versionId" placeholder="MJ版本ID" />
</n-form-item>
</div>
<n-spin :show="show" size="large">
<div style="overflow: auto; height: 100%">
<n-card title="基础设置" size="medium" hoverable style="min-width: 850px">
<n-form :model="mjSetting" ref="sampleRef" :rules="sampleRules">
<div style="display: flex; align-items: center">
<n-form-item label="出图模式" style="width: 150px" path="requestModel">
<n-select
:options="request_model_options"
v-model:value="mjSetting.requestModel"
placeholder="请选择出图模式"
></n-select>
</n-form-item>
<n-form-item
label="选择生图机器人"
path="selectRobot"
style="width: 120px; margin-left: 10px"
>
<n-select
:options="select_robot_options"
v-model:value="mjSetting.selectRobot"
@update:value="UpdateSelectRobot"
></n-select>
</n-form-item>
<n-form-item
label="机器人模型"
style="width: 120px; margin-left: 10px"
path="imageModel"
>
<n-select
placeholder="请选择机器人模型"
:options="image_model_options"
v-model:value="mjSetting.imageModel"
></n-select>
</n-form-item>
<n-form-item label="生图尺寸" style="width: 120px; margin-left: 10px" path="imageScale">
<n-select
placeholder="请选择生图尺寸"
:options="image_scale_options"
v-model:value="mjSetting.imageScale"
></n-select>
</n-form-item>
<n-form-item
label="命令后缀"
style="width: 160px; margin-left: 10px"
path="image_suffix"
>
<n-input v-model:value="image_suffix" placeholder="请输入后缀命令"></n-input>
</n-form-item>
<n-form-item
label="生图任务量"
style="width: 100px; margin-left: 10px"
path="taskCount"
>
<n-input-number
v-model:value="mjSetting.taskCount"
:show-button="false"
placeholder="MJ并发出图数量"
:min="1"
:max="20"
></n-input-number>
</n-form-item>
<n-form-item
label="间隔时间(s)"
style="width: 100px; margin-left: 10px"
path="spaceTime"
>
<n-input-number
v-model:value="mjSetting.spaceTime"
:show-button="false"
placeholder="请输入间隔时间(s)"
:min="1"
:max="30"
></n-input-number>
</n-form-item>
</div>
</n-form>
</n-card>
<n-card
title="API模式设置"
hoverable
style="margin-top: 10px; min-width: 850px"
size="medium"
>
<n-form :model="mjSetting.apiSetting">
<div style="display: flex">
<n-form-item
label="选择出图的API"
style="width: 160px; margin-left: 10px"
path="mjApiUrl"
>
<n-select
:options="mj_api_options"
v-model:value="mjSetting.apiSetting.mjApiUrl"
placeholder="选择出图的中转API"
/>
</n-form-item>
<n-form-item style="margin-left: 10px" path="mj_api_url">
<n-button type="success" @click="openGptBuyUrl">购买</n-button>
</n-form-item>
<n-form-item
label="选择出图速度模式"
style="width: 160px; margin-left: 10px"
path="mjSpeed"
>
<n-select
:options="mj_speed_options"
v-model:value="mjSetting.apiSetting.mjSpeed"
placeholder="选择出图速度模式"
/>
</n-form-item>
<n-form-item label="输入API密钥" style="width: 160px; margin-left: 10px" path="apiKey">
<n-input
type="password"
placeholder="请输入密钥"
v-model:value="mjSetting.apiSetting.apiKey"
></n-input>
</n-form-item>
</div>
</n-form>
</n-card>
<div style="display: flex">
<n-form-item label="NIJI机器ID" path="niji.botId">
<n-input v-model:value="mjSetting.niji.botId" placeholder="NIJI机器ID" />
</n-form-item>
<n-form-item label="NIJI命令ID" style="margin-left: 10px" path="niji.commandId">
<n-input v-model:value="mjSetting.niji.commandId" placeholder="NIJI命令ID" />
</n-form-item>
<n-form-item label="NIJI命令名称" style="margin-left: 10px" path="niji.commandName">
<n-input v-model:value="mjSetting.niji.commandName" placeholder="NIJI命令名称" />
</n-form-item>
<n-form-item label="NIJI版本ID" style="margin-left: 10px" path="niji.versionId">
<n-input v-model:value="mjSetting.niji.versionId" placeholder="NIJI版本ID" />
</n-form-item>
</div> -->
<n-card title="代理模式设置" hoverable style="margin-top: 10px; min-width: 850px">
<n-form :model="mjSetting.remoteSetting">
<div style="display: flex; margin-top: 10px">
<n-form-item label="服务器ID" style="width: 200px; margin-left: 5px" path="guildId">
<n-input
v-model:value="mjSetting.remoteSetting.guildId"
placeholder="请填写服务器ID"
/>
</n-form-item>
<n-form-item label="频道ID" style="width: 200px; margin-left: 10px" path="channelId">
<n-input
v-model:value="mjSetting.remoteSetting.channelId"
placeholder="请填写频道ID"
/>
</n-form-item>
<n-form-item
label="MJ私信ID"
style="width: 200px; margin-left: 10px"
path="mjBotChannelId"
>
<n-input
v-model:value="mjSetting.remoteSetting.mjBotChannelId"
placeholder="请填写MJ私信ID"
/>
</n-form-item>
<n-form-item
label="Niji私信ID"
style="width: 200px; margin-left: 10px"
path="nijiBotChannelId"
>
<n-input
v-model:value="mjSetting.remoteSetting.nijiBotChannelId"
placeholder="请填写NIJI私信ID"
/>
</n-form-item>
<n-form-item style="width: 200px; margin-left: 10px">
<n-button type="info" @click="AccountSync">账号同步</n-button>
</n-form-item>
</div>
<div style="display: flex; margin-top: 10px">
<n-form-item label="用户token" style="width: 240px" path="token">
<n-input
v-model:value="mjSetting.remoteSetting.userToken"
placeholder="请填写MJtoken"
/>
</n-form-item>
<n-form-item label="用户Agent" style="width: 250px; margin-left: 10px" path="userAgent">
<n-input
v-model:value="mjSetting.remoteSetting.userAgent"
placeholder="请填写用户Agent"
/>
</n-form-item>
<n-form-item label="账号并发数" style="width: 100px; margin-left: 10px" path="coreSize">
<n-input-number
v-model:value="mjSetting.remoteSetting.coreSize"
:show-button="false"
placeholder="请填写账号并发数"
:min="1"
:max="20"
></n-input-number>
</n-form-item>
<n-form-item label="等待队列" style="width: 100px; margin-left: 10px" path="queueSize">
<n-input-number
v-model:value="mjSetting.remoteSetting.queueSize"
:show-button="false"
placeholder="请填写等待队列数量"
:min="1"
:max="20"
></n-input-number>
</n-form-item>
<n-form-item
label="任务超时时间"
style="width: 100px; margin-left: 10px"
path="timeoutMinutes"
>
<n-input-number
v-model:value="mjSetting.remoteSetting.timeoutMinutes"
:show-button="false"
placeholder="请填写任务超时时间"
:min="1"
:max="20"
></n-input-number>
</n-form-item>
</div>
</n-form>
</n-card>
<n-form-item label="用户token" style="width: 810px" path="token">
<n-input v-model:value="mjSetting.token" placeholder="登录MJ后切换服务器自动获取" />
</n-form-item>
<n-form-item label="用户Agent" style="width: 810px" path="userAgent.userAgent">
<n-input
v-model:value="mjSetting.userAgent.userAgent"
placeholder="登录MJ后切换服务器自动获取(可自定义)"
style="margin-right: 10px"
/>
<n-tooltip trigger="hover" style="background-color: aliceblue; color: black">
<template #trigger>
<n-checkbox v-model:checked="mjSetting.userAgent.customize" style="width: 100px">
自定义
</n-checkbox>
</template>
开启自定义需要手动填写userAgent可以填入浏览器的userAgent
</n-tooltip>
</n-form-item>
<div style="display: flex; align-items: center">
<n-form-item label="选择生图机器人" path="select_robot" style="width: 120px">
<n-select
:options="select_robot_options"
v-model:value="mjSetting.select_robot"
@update:value="UpdateSelectRobot"
></n-select>
</n-form-item>
<n-form-item label="机器人模型" style="width: 120px; margin-left: 10px" path="image_scale">
<n-select
placeholder="请选择机器人模型"
:options="image_model_options"
v-model:value="mjSetting.image_model"
></n-select>
</n-form-item>
<n-form-item label="生图尺寸" style="width: 120px; margin-left: 10px" path="image_scale">
<n-select
placeholder="请选择生图尺寸"
:options="image_scale_options"
v-model:value="mjSetting.image_scale"
></n-select>
</n-form-item>
<n-form-item label="命令后缀" style="width: 160px; margin-left: 10px" path="image_suffix">
<n-input v-model:value="image_suffix" placeholder="请输入后缀命令"></n-input>
</n-form-item>
<n-form-item label="生图任务量" style="width: 100px; margin-left: 10px" path="task_count">
<n-input-number
v-model:value="mjSetting.task_count"
:show-button="false"
placeholder="MJ并发出图数量"
:min="1"
:max="10"
></n-input-number>
</n-form-item>
<n-form-item label="间隔时间(s)" style="width: 100px; margin-left: 10px" path="space_time">
<n-input-number
v-model:value="mjSetting.space_time"
:show-button="false"
placeholder="请输入间隔时间(s)"
:min="1"
:max="20"
></n-input-number>
</n-form-item>
<n-card title="浏览器模式设置" hoverable style="margin-top: 10px; min-width: 850px">
<n-form :model="mjSetting.browserSetting">
<div style="display: flex; margin-top: 10px">
<n-form-item>
<n-button type="info" @click="OpenDiscordWindow">打开登录MJ</n-button>
</n-form-item>
<n-form-item label="服务器ID" style="width: 200px; margin-left: 5px" path="serviceId">
<n-input
v-model:value="mjSetting.browserSetting.serviceId"
placeholder="登录MJ后切换服务器自动获取"
/>
</n-form-item>
<n-form-item label="频道ID" style="width: 200px; margin-left: 10px" path="channelId">
<n-input
v-model:value="mjSetting.browserSetting.channelId"
placeholder="登录MJ后切换频道自动获取"
/>
</n-form-item>
<n-form-item label="用户token" style="width: 300px; margin-left: 10px" path="token">
<n-input
v-model:value="mjSetting.browserSetting.token"
placeholder="登录MJ后切换服务器自动获取"
/>
</n-form-item>
</div>
<n-form-item label="用户Agent" style="width: 810px" path="userAgent">
<n-input
v-model:value="mjSetting.browserSetting.userAgent"
placeholder="登录MJ后切换服务器自动获取(可自定义)"
style="margin-right: 10px"
/>
<n-tooltip trigger="hover" style="background-color: aliceblue; color: black">
<template #trigger>
<n-checkbox
v-model:checked="mjSetting.browserSetting.userAgentCustom"
style="width: 100px"
>
自定义
</n-checkbox>
</template>
开启自定义需要手动填写userAgent可以填入浏览器的userAgent
</n-tooltip>
</n-form-item>
</n-form>
</n-card>
<n-button type="info" round @click="SaveMjSetting" style="margin-top: 10px"
>保存MJ配置</n-button
>
</div>
<div style="display: flex">
<n-form-item label="出图模式" style="width: 150px" path="request_model">
<n-select
:options="request_model_options"
v-model:value="mjSetting.request_model"
placeholder="请选择出图模式"
></n-select>
</n-form-item>
<n-form-item label="选择出图的API" style="width: 160px; margin-left: 10px" path="mj_api_url">
<n-select
:options="mj_api_options"
v-model:value="mjSetting.mj_api_url"
placeholder="选择出图的中转API"
/>
</n-form-item>
<n-form-item style="margin-left: 10px" path="mj_api_url">
<n-button type="success" @click="openGptBuyUrl">购买</n-button>
</n-form-item>
<n-form-item label="选择出图速度模式" style="width: 160px; margin-left: 10px" path="mj_speed">
<n-select
:options="mj_speed_options"
v-model:value="mjSetting.mj_speed"
placeholder="选择出图速度模式"
/>
</n-form-item>
<n-form-item label="输入API密钥" style="width: 160px; margin-left: 10px" path="mj_speed">
<n-input
type="password"
placeholder="请输入密钥"
v-model:value="mjSetting.api_key"
></n-input>
</n-form-item>
</div>
</n-form>
<template #description> 正在添加或同步MJ账号信息 </template>
</n-spin>
</template>
<script>
import { defineComponent, ref, onMounted, computed, toRaw } from 'vue'
import { defineComponent, ref, onMounted, computed, toRaw, h } from 'vue'
import {
NButton,
useMessage,
useDialog,
NDataTable,
NForm,
NFormItem,
@@ -157,11 +275,14 @@ import {
NSelect,
NTooltip,
NIcon,
NInputNumber
NInputNumber,
NCard,
NSpin
} from 'naive-ui'
import { DEFINE_STRING } from '../../../../define/define_string'
import { Reload } from '@vicons/ionicons5'
import { isEmpty, max, min } from 'lodash'
import { MJImageType } from '../../../../define/enum/mjEnum'
export default defineComponent({
components: {
NButton,
@@ -175,11 +296,15 @@ export default defineComponent({
NTooltip,
NIcon,
Reload,
NInputNumber
NInputNumber,
NCard,
NSpin
},
setup() {
let message = useMessage()
let formRef = ref(null)
let dialog = useDialog()
let sampleRef = ref(null)
let show = ref(false)
let select_robot_options = ref([
{
label: 'MJ',
@@ -203,35 +328,48 @@ export default defineComponent({
])
let mjSetting = ref({
serviceID: null,
channelID: null,
mj: {
botId: null,
commandId: null,
commandName: null,
versionId: null
},
niji: {
botId: null,
commandId: null,
commandName: null,
versionId: null
},
token: null,
userAgent: {
id: null,
imageModel: null,
imageScale: null,
imageSuffix: null,
requestModel: null,
type: null,
selectRobot: null,
spaceTime: 6,
taskCount: 3,
createTime: null,
updateTime: null,
version: null,
remoteSetting: {
accountId: null,
channelId: null,
coreSize: 3,
guildId: null,
mjBotChannelId: null,
nijiBotChannelId: null,
queueSize: 6,
remark: null, // 机器码
remixAutoSubmit: false,
timeoutMinutes: 6,
userAgent: null,
customize: false
userToken: null
},
select_robot: null,
image_scale: null,
image_model: null,
image_suffix: null,
task_count: 3,
space_time: 5,
request_model: null,
mj_api_url: null,
mj_speed: null,
api_key: null
apiSetting: {
id: null,
mjApiUrl: null,
mjSpeed: null,
apiKey: null
},
browserSetting: {
id: null,
serviceId: null,
channelId: null,
mjBotId: null,
nijBotId: null,
token: null,
userAgent: null,
userAgentCustom: false
}
})
let image_scale_options = ref([])
@@ -241,42 +379,43 @@ export default defineComponent({
let mj_api_options = ref([])
let image_suffix = computed(() => {
let text = image_model_options.value.findIndex((item) => {
return item.value == mjSetting.value.image_model
return item.value == mjSetting.value.imageModel
})
if (text == -1) {
return
}
let sc = image_scale_options.value.findIndex((item) => {
return item.value == mjSetting.value.image_scale
return item.value == mjSetting.value.imageScale
})
let dd = ` --${image_model_options.value[text].text} --ar ${image_scale_options.value[sc].text}`
mjSetting.value.image_suffix = dd
mjSetting.value.imageSuffix = dd
return dd
})
// 初始化现在设置的数据
async function InitData() {
// 获取当前mj配置信息
await window.api.GetDefineConfigJsonByProperty(
JSON.stringify(['img_base', 'mj_config', false, null]),
(value) => {
console.log(value)
if (value.code == 0) {
message.error(value.message)
return
}
// 判断是不是有数据
if (value.data) {
mjSetting.value = Object.assign(mjSetting.value, value.data)
if (mjSetting.value.select_robot != 'mj' && mjSetting.value.select_robot != 'niji') {
mjSetting.value.select_robot = null
}
}
}
)
debugger
// 获取到的是当前的配置信息
let res = await window.setting.GetMJSettingTreeData()
if (res.code == 0) {
message.error(res.message)
return
}
if (!res.data.apiSetting) {
delete res.data.apiSetting
}
if (!res.data.remoteSetting) {
delete res.data.remoteSetting
}
if (!res.data.browserSetting) {
delete res.data.browserSetting
}
mjSetting.value = Object.assign(mjSetting.value, res.data)
console.log(res)
await window.mj.GetMJImageScale((value) => {
if (value.code == 0) {
@@ -284,8 +423,8 @@ export default defineComponent({
return
}
image_scale_options.value = value.data
if (image_scale_options.value.length > 0 && mjSetting.value.image_scale == null) {
mjSetting.value.image_scale = image_scale_options.value[0].value
if (image_scale_options.value.length > 0 && mjSetting.value.imageScale == null) {
mjSetting.value.imageScale = image_scale_options.value[0].value
}
})
@@ -296,8 +435,8 @@ export default defineComponent({
}
image_model_options.value = value.data
tmp_image_model_options = value.data
if (image_model_options.value.length > 0 && mjSetting.value.image_model == null) {
mjSetting.value.image_model = image_model_options.value[0].value
if (image_model_options.value.length > 0 && mjSetting.value.imageModel == null) {
mjSetting.value.imageModel = image_model_options.value[0].value
}
})
@@ -307,8 +446,8 @@ export default defineComponent({
return
}
request_model_options.value = value.data.filter((item) => !item.disable)
if (request_model_options.value.length > 0 && mjSetting.value.request_model == null) {
mjSetting.value.request_model = request_model_options.value[0].value
if (request_model_options.value.length > 0 && mjSetting.value.requestModel == null) {
mjSetting.value.requestModel = request_model_options.value[0].value
}
})
@@ -318,15 +457,16 @@ export default defineComponent({
return
}
mj_api_options.value = value.data.filter((item) => item.mj_url)
if (mj_api_options.value.length > 0 && mjSetting.value.mj_api_url == null) {
mjSetting.value.mj_api_url = mj_api_options.value[0].value
if (mj_api_options.value.length > 0 && mjSetting.value.apiSetting.mjApiUrl == null) {
mjSetting.value.apiSetting.mjApiUrl = mj_api_options.value[0].value
}
})
}
onMounted(async () => {
// 监听修改当前界面的数据,后续可以将数据保存到本地配置
// 监听浏览器设置的中信息
window.api.setEventListen([DEFINE_STRING.DISCORD.OPERATE_REFRASH_DISCORD_URL], (value) => {
debugger
if (value.code == 0) {
message.error(value.message)
return
@@ -334,12 +474,12 @@ export default defineComponent({
// 保存数据
console.log(value)
if (value.type == DEFINE_STRING.DISCORD_SIMPLE_DATA_TYPE.URL) {
mjSetting.value.serviceID = value.data.serviceID
mjSetting.value.channelID = value.data.channelID
mjSetting.value.browserSetting.serviceId = value.data.serviceID
mjSetting.value.browserSetting.channelId = value.data.channelID
} else if (value.type == DEFINE_STRING.DISCORD_SIMPLE_DATA_TYPE.TOKEN) {
mjSetting.value.token = value.data.authorization
if (!mjSetting.value.userAgent.customize) {
mjSetting.value.userAgent.userAgent = value.data.userAgent
mjSetting.value.browserSetting.token = value.data.authorization
if (!mjSetting.value.browserSetting.userAgentCustom) {
mjSetting.value.browserSetting.userAgent = value.data.userAgent
}
} else {
message.error('未知的数据类型')
@@ -348,8 +488,8 @@ export default defineComponent({
await InitData()
if (mjSetting.value.mj_speed == null) {
mjSetting.value.mj_speed = mj_speed_options.value[0].value
if (mjSetting.value.apiSetting.mjSpeed == null) {
mjSetting.value.apiSetting.mjSpeed = mj_speed_options.value[0].value
}
})
@@ -365,135 +505,98 @@ export default defineComponent({
})
}
/**
* 获取频道机器人
*/
async function GetChannelRobots() {
// 判断是不是有数据(服务器ID,频道ID,用户token,用户Agent
if (
isEmpty(mjSetting.value.serviceID) &&
isEmpty(mjSetting.value.channelID) &&
isEmpty(mjSetting.value.token) &&
isEmpty(mjSetting.value.userAgent.userAgent)
) {
message.error('请先填写或获取完整的数据(服务器ID,频道ID,用户token,用户Agent)')
return
}
const headers = {
authorization: mjSetting.value.token
}
await fetch(
`https://discord.com/api/v9/guilds/${mjSetting.value.serviceID}/application-command-index`,
{
method: 'GET',
headers: headers
}
)
.then((response) => response.json())
.then((data) => {
// 修改配置信息(判断是不是niji或者是mj)
// 填充mjniji数据
if (data.applications && data.application_commands) {
let mj_inedx = data.applications.findIndex((item) => {
return item.name.toLowerCase().startsWith('midjourney')
})
if (mj.index != -1) {
mjSetting.value.mj.botId = data.applications[mj_inedx].id
let f = data.application_commands.find((a) => {
return a.name == 'imagine' && a.application_id == data.applications[mj_inedx].id
})
mjSetting.value.mj.commandId = f?.id
mjSetting.value.mj.commandName = 'imagine'
mjSetting.value.mj.versionId = f?.version
}
let niji_inedx = data.applications.findIndex((item) => {
return item.name.toLowerCase().startsWith('niji')
})
if (mj.index != -1) {
mjSetting.value.niji.botId = data.applications[niji_inedx].id
let f = data.application_commands.find((a) => {
return a.name == 'imagine' && a.application_id == data.applications[niji_inedx].id
})
mjSetting.value.niji.commandId = f?.id
mjSetting.value.niji.commandName = 'imagine'
mjSetting.value.niji.versionId = f?.version
}
}
})
.catch((error) => {
window.api.showGlobalNotificationDialog({
code: 0,
message: '获取频道机器人请求失败,错误信息如下: ' + error.message.toString()
})
return
})
// 基础配置的必填检测
let sampleRules = {
imageModel: [{ required: true, message: '请选择机器人模型', trigger: 'blur' }],
imageScale: [{ required: true, message: '请选择生图尺寸', trigger: 'blur' }],
requestModel: [{ required: true, message: '请选择出图模式', trigger: 'blur' }],
selectRobot: [{ required: true, message: '请选择生图机器人', trigger: 'blur' }]
}
/**
* 保存MJ配置
*/
async function SaveMjSetting(e) {
// 在保存的时候要进行数据保存
debugger
e.preventDefault()
formRef.value?.validate(async (errors) => {
sampleRef.value?.validate(async (errors) => {
if (errors) {
message.error('请检查必填字段')
return
}
mjSetting.value.image_suffix = image_suffix.value
await window.api.SaveDefineConfigJsonByProperty(
JSON.stringify(['img_base', 'mj_config', toRaw(mjSetting.value), false]),
(value) => {
console.log(value)
if (value.code == 0) {
message.error(value.message)
return
}
message.success(value.message)
mjSetting.value.imageSuffix = image_suffix.value
// 通过选择的请求模式判断哪些是要校验的
let request_model = mjSetting.value.requestModel
if (request_model == MJImageType.API_MJ) {
// API模式,检查必填数据
if (
mjSetting.value.apiSetting == null ||
mjSetting.value.apiSetting.mjApiUrl == null ||
mjSetting.value.apiSetting.mjSpeed == null ||
mjSetting.value.apiSetting.apiKey == null
) {
message.error('请检查API模式设置的必填字段')
return
}
)
})
}
let ruleObj = (errorMessage) => {
return [
{
required: true,
validator(rule, value) {
if (value == null || value == '') return new Error(errorMessage)
return true
},
trigger: ['input', 'blur', 'change']
}
]
}
let rules = {
serviceID: ruleObj('必填服务器ID'),
channelID: ruleObj('必填频道ID'),
'mj.botId': ruleObj('必填MJ机器人ID'),
'mj.commandId': ruleObj('必填MJ命令ID'),
'mj.commandName': ruleObj('必填Mj命令名称'),
'mj.versionId': ruleObj('必填MJ版本ID'),
'niji.botId': ruleObj('必填NIJI机器人ID'),
'niji.commandId': ruleObj('必填NIJI命令ID'),
'niji.commandName': ruleObj('必填NIJI命令名称'),
'niji.versionId': ruleObj('必填NIJI版本ID'),
token: ruleObj('必填用户token'),
'userAgent.userAgent': ruleObj('必填用户Agent'),
select_robot: ruleObj('必填选择生图机器人'),
image_scale: ruleObj('必填生图尺寸'),
image_model: ruleObj('必填机器人模型'),
image_suffix: ruleObj('必填命令后缀'),
task_count: ruleObj('必填生图任务量'),
space_time: ruleObj('必填间隔时间(s)'),
request_model: ruleObj('必填出图模式'),
mj_api_url: ruleObj('必填选择出图的API'),
mj_speed: ruleObj('必填选择出图速度模式')
if (request_model == MJImageType.REMOTE_MJ) {
if (mjSetting.value.remoteSetting == null) {
message.error('请先添加代理模式的配置')
return
}
// if (mjSetting.value.remoteSetting.accountId == null) {
// message.error('请先同步账号')
// return
// }
// 代理模式,检查必填数据
if (
mjSetting.value.remoteSetting == null ||
mjSetting.value.remoteSetting.guildId == null ||
mjSetting.value.remoteSetting.channelId == null ||
mjSetting.value.remoteSetting.userToken == null ||
mjSetting.value.remoteSetting.userAgent == null
) {
message.error('请检查代理模式设置的必填字段')
return
}
}
if (request_model == MJImageType.BROWSER_MJ) {
// 浏览器模式,检查必填数据
if (
mjSetting.value.browserSetting == null ||
mjSetting.value.browserSetting.serviceId == null ||
mjSetting.value.browserSetting.channelId == null ||
mjSetting.value.browserSetting.token == null ||
mjSetting.value.browserSetting.userAgent == null
) {
message.error('请检查浏览器模式设置的必填字段')
return
}
}
// 开始保存数据
let res = await window.setting.SaveMJSettingTreeData(toRaw(mjSetting.value))
if (res.code == 0) {
window.api.showGlobalMessageDialog({ code: 0, message: res.message })
return
}
mjSetting.value = res.data
// 判断当前的模式
if (mjSetting.value.requestModel == MJImageType.REMOTE_MJ) {
window.api.showGlobalMessageDialog({
code: 1,
message: `数据保存成功,
当前生图模式为代理模式,若有修改配置请手动同步账号数据,但是不要频繁同步,有封号风险 `
})
} else {
window.api.showGlobalMessageDialog({ code: 1, message: '添加成功' })
}
})
}
/**
@@ -508,10 +611,10 @@ export default defineComponent({
// 判断当前选中的机器人是不是在当前的数据中
if (
image_model_options.value.findIndex((item) => {
return item.value == mjSetting.value.image_model
return item.value == mjSetting.value.imageModel
}) == -1
) {
mjSetting.value.image_model =
mjSetting.value.imageModel =
image_model_options.value.length > 0 ? image_model_options.value[0].value : null
}
}
@@ -520,8 +623,9 @@ export default defineComponent({
* 打开购买GPT的地址
*/
async function openGptBuyUrl() {
let tmp_gb = mj_api_options.value.filter((item) => item.value == mjSetting.value.mj_api_url)
let tmp_gb = mj_api_options.value.filter(
(item) => item.value == mjSetting.value.apiSetting.mjApiUrl
)
if (tmp_gb.length == 0) {
message.error('当前选择的服务商没有购买地址!')
return
@@ -534,14 +638,59 @@ export default defineComponent({
}
}
/**
* 账号同步
*/
async function AccountSync() {
dialog.warning({
title: '警告',
content: () =>
h('div', {}, [
h(
'span',
{},
{
default: () => '同步数据的信息是保存后的数据'
}
),
h('br'),
h(
'span',
{ style: 'color : red;font-size : 18px' },
{
default: () => '修改数据后请先保存,请先保存再执行同步操作'
}
),
h('br'),
h(
'span',
{},
{
default: () => '同步操作不要频繁,有封号风险'
}
)
]),
positiveText: '确定',
negativeText: '取消',
onPositiveClick: async () => {
show.value = true
let res = await window.setting.MjRemoteAccountSync()
show.value = false
if (res.code == 0) {
message.error(res.message)
return
}
message.success('MJ账号同步成功,可以开始使用')
}
})
}
return {
OpenDiscordWindow,
mjSetting,
select_robot_options,
GetChannelRobots,
SaveMjSetting,
rules,
formRef,
sampleRef,
image_scale_options,
image_model_options,
UpdateSelectRobot,
@@ -549,7 +698,10 @@ export default defineComponent({
request_model_options,
mj_api_options,
mj_speed_options,
openGptBuyUrl
openGptBuyUrl,
sampleRules,
AccountSync,
show
}
}
})
@@ -198,6 +198,7 @@ import AddGptOption from './Components/AddGptOption.vue'
import { FolderOpenSharp as FolderOpen } from '@vicons/ionicons5'
import AddGptPrompts from './Components/AddGptPrompts.vue'
import { isEmpty } from 'lodash'
import { useSoftwareStore } from '../../../../stores/software'
export default defineComponent({
components: {
@@ -216,6 +217,7 @@ export default defineComponent({
},
setup() {
let formRef = ref(null)
let softwareStore = useSoftwareStore()
let message = useMessage()
let formValue = ref({
draft_path: window.config.draft_path,
@@ -230,7 +232,7 @@ export default defineComponent({
translation_app_id: window.config.translation_app_id,
translation_secret: window.config.translation_secret,
translation_auto: window.config.translation_auto,
theme: window.config.theme,
theme: softwareStore.softWare.theme,
character_select_model: window.config.character_select_model,
window_wh_bm_remember: window.config.window_wh_bm_remember
})
@@ -240,12 +242,10 @@ export default defineComponent({
let character_select_model_options = ref([])
let dialog = useDialog()
let loading = ref(false)
/**
* 加载GPT的配置信息
*/
async function InitGptOptions() {
await window.api.getGptBusinessOption('all', (value) => {
if (value.code == 0) {
message.error(value.message)
@@ -327,9 +327,9 @@ export default defineComponent({
/**
* 保存配置信息
*/
function handleValidateButtonClick(e) {
async function handleValidateButtonClick(e) {
e.preventDefault()
formRef.value?.validate((errors) => {
formRef.value?.validate(async (errors) => {
if (errors) {
message.error('请检查必填字段')
return
@@ -345,6 +345,8 @@ export default defineComponent({
window.api.showGlobalMessageDialog({ code: 0, message: value.message })
}
})
softwareStore.SetSoftware({ theme: formValue.value.theme })
await softwareStore.SaveSoftware()
})
}
@@ -368,7 +370,6 @@ export default defineComponent({
* 打开购买GPT的地址
*/
async function openGptBuyUrl() {
let tmp_gb = gpt_options.value.filter((item) => item.value == formValue.value.gpt_business)
if (tmp_gb.length == 0) {
message.error('当前选择的服务商没有购买地址!')
@@ -387,7 +388,6 @@ export default defineComponent({
* @param {*} value 主题名称
*/
async function ChangeMode(value) {
console.log(value)
const isDarkMode = await window.darkMode.toggle(value)
}
@@ -486,7 +486,8 @@ export default defineComponent({
loading,
SelectProjectFolder,
AddGptPrompt,
character_select_model_options
character_select_model_options,
softwareStore
}
}
})
+2
View File
@@ -26,6 +26,8 @@ const routes = [
{ path: "/ShowMessage", name: "ShowMessage", component: () => import('./components/Home/ShowMessage.vue') },
{ path: "/sdoriginal", name: "sdoriginal", component: () => import('./components/Original/MainPage.vue') },
{ path: "/mj_setting", name: "mj_setting", component: () => import('./components/Setting/MJSetting.vue') },
{ path: '/reverse_management', name: "reverse_management", component: () => import('./components/ReverseManage/ReverseManage.vue') },
{ path: '/manage_book/:id', name: "manage_book", component: () => import('./components/ReverseManage/ManageBookDetail.vue') },
]
},
{ path: "/ReDrawImage", component: () => import('./components/Home/ReDrawImageWD.vue'), },