1. 添加软件高清倍率设置,实现自定义高清倍率(支持两倍、三倍和四倍,默认是两倍)
2. (聚合推文)新增导出草稿。可以依赖做好的草稿文件,只替换图片文件
3. (聚合推文)新增批量生成草稿
4. (聚合推文)修改小说批次任务进行详细界面操作为双击
This commit is contained in:
2024-10-23 22:59:29 +08:00
parent f4d042f699
commit 0c5988ed41
22 changed files with 1436 additions and 1225 deletions
File diff suppressed because it is too large Load Diff
@@ -48,7 +48,6 @@ export default defineComponent({
props: ['bookTask'],
setup(props) {
let message = useMessage()
let dialog = useDialog()
let bookTask = ref(props.bookTask)
@@ -63,7 +62,6 @@ export default defineComponent({
* @param e
*/
async function ReSetBookTaskDetail(e) {
e.stopPropagation()
dialog.warning({
title: '重置小说任务',
@@ -115,15 +113,28 @@ export default defineComponent({
}
async function hdImageFunc(id, operateBookType) {
softwareStore.spin.spinning = true
softwareStore.spin.tip = '正在高清中。。。'
let res = await window.book.HDImage(id, 4, operateBookType)
softwareStore.spin.spinning = false
if (res.code == 1) {
message.success('高清成功')
} else {
message.error(res.message)
}
let da = dialog.warning({
title: '高清提示',
content: `是否确认高清,当前的高清倍数为 ${softwareStore.globalSetting.hdScale} 倍,是否继续?`,
positiveText: '继续',
negativeText: '取消',
onPositiveClick: async () => {
da.destroy()
softwareStore.spin.spinning = true
softwareStore.spin.tip = '正在高清中。。。'
let res = await window.book.HDImage(
id,
softwareStore.globalSetting.hdScale ?? 2,
operateBookType
)
softwareStore.spin.spinning = false
if (res.code == 1) {
message.success('高清成功')
} else {
message.error(res.message)
}
}
})
}
/**
@@ -171,10 +182,10 @@ export default defineComponent({
*/
async function ClipDraft(e) {
e.stopPropagation()
dialog.info({
closeOnEsc: false,
title: '生成草稿前检查',
title: `生成草稿前检查 ${bookTask.value.name}`,
maskClosable: false,
content: () =>
h(ManageBookTaskGenerateInformation, { bookTask: bookTask.value, type: 'bookTask' })
@@ -46,15 +46,30 @@
clearable
/>
</n-form-item>
<n-form-item label="选择剪映草稿" path="backgroundMusic">
<div>
<div style="color: red">
注意选择的草稿主轨道的图片数量要和当前的相同会生成新的草稿并且只会替换图片保留其余的数据
</div>
<n-select
style="width: 300px"
v-model:value="bookTask.draftDepend"
filterable
placeholder="选择样式"
:options="draftSelect"
clearable
/>
</div>
</n-form-item>
<n-form-item path="backgroundMusic">
<n-button :disabled="type == 'book'" type="info" @click="UseBookVideoDataToBookTask">{{
type == bookTask ? '应用主小说相关数据' : '当前就是用的主小说的数据'
}}</n-button>
<n-button :disabled="type == 'book'" type="info" @click="UseBookVideoDataToBookTask"
>应用主小说相关数据</n-button
>
<n-button type="info" style="margin-left: 10px" @click="SaveVideoData">保存数据</n-button>
</n-form-item>
<div v-if="type == 'bookTask'" style="color: red">注意在生成草稿前要先保存数据</div>
<div v-else style="color: red">
注意在生成草稿前要先保存数据当前会生成全部的草稿全部会使用上面的参数
注意在生成草稿前要先保存数据当前会生成选择的草稿全部会使用上面的参数
</div>
<n-form-item style="display: flex; justify-content: flex-end">
<n-button type="info" style="margin-left: 10px" @click="AddJianyingDraft">生成草稿</n-button>
@@ -62,136 +77,166 @@
</n-form>
</template>
<script>
import { ref, onMounted, defineComponent, onUnmounted, toRaw, watch } from 'vue'
<script setup>
import { ref, onMounted } from 'vue'
import { useMessage, NForm, NFormItem, NButton, NIcon, NInput, NSelect } from 'naive-ui'
import { FolderOpen } from '@vicons/ionicons5'
import { OperateBookType } from '../../../../../../define/enum/bookEnum'
import { useReverseManageStore } from '../../../../../../stores/reverseManage'
export default defineComponent({
components: { NForm, NFormItem, NButton, NIcon, NInput, NSelect, FolderOpen },
props: ['bookTask', 'type'],
setup(props) {
let bookTask = ref(props.bookTask)
let type = ref(props.type)
let backgroundMusicOptions = ref([])
let message = useMessage()
onMounted(async () => {
// 获取初始化的背景音乐列表
await window.api.GetBackgroundMusicConfigList((value) => {
if (value.code == 0) {
message.error(value.message)
return
}
for (let i = 0; i < value.value.length; i++) {
const element = value.value[i]
let obj = {
label: element.name,
value: element.id
}
backgroundMusicOptions.value.push(obj)
}
})
let props = defineProps({
bookTask: undefined,
type: undefined,
selectBookTask: []
})
let bookTask = ref(props.bookTask)
let type = ref(props.type)
let backgroundMusicOptions = ref([])
let message = useMessage()
let draftSelect = ref([])
let reverseManageStore = useReverseManageStore()
onMounted(async () => {
// 获取草稿文件列表
window.api.getDraftFileList((value) => {
value.forEach((element) => {
let obj = {
label: element,
value: element
}
draftSelect.value.push(obj)
})
/**
* 选择对应的字幕文件
*/
async function SelectSrtFile() {
window.api.SelectFile(['srt'], (value) => {
if (value.code == 0) {
message.error(value.message)
return
}
bookTask.value.srtPath = value.value
})
})
// 获取初始化的背景音乐列表
await window.api.GetBackgroundMusicConfigList((value) => {
if (value.code == 0) {
message.error(value.message)
return
}
/**
* 选择对应的配音文件
*/
async function SelectMusicFile() {
window.api.SelectFile(['mp3', 'wav'], (value) => {
if (value.code == 0) {
message.error(value.message)
return
}
bookTask.value.audioPath = value.value
})
}
/**
* 应用主小说相关数据
*/
async function UseBookVideoDataToBookTask() {
if (type.value == 'book') {
message.error('当前状态这个按钮不可用')
return
}
let res = await window.book.UseBookVideoDataToBookTask(
bookTask.value.id,
OperateBookType.BOOKTASK
)
if (res.code == 0) {
message.error(res.message)
} else {
// 将数据写回去
bookTask.value.backgroundMusic = res.data.backgroundMusic
bookTask.value.friendlyReminder = res.data.friendlyReminder
bookTask.value.draftSrtStyle = res.data.draftSrtStyle
bookTask.value.srtPath = res.data.srtPath
bookTask.value.audioPath = res.data.audioPath
message.success('应用主小说相关数据成功')
for (let i = 0; i < value.value.length; i++) {
const element = value.value[i]
let obj = {
label: element.name,
value: element.id
}
backgroundMusicOptions.value.push(obj)
}
})
})
/**
* 保存数据
*/
async function SaveVideoData() {
let res = await window.db.UpdateBookTaskData(bookTask.value.id, {
srtPath: bookTask.value.srtPath,
audioPath: bookTask.value.audioPath,
backgroundMusic: bookTask.value.backgroundMusic,
friendlyReminder: bookTask.value.friendlyReminder,
draftSrtStyle: bookTask.value.draftSrtStyle
})
if (res.code == 0) {
message.error('保存小说批次数据失败')
} else {
message.success('保存小说批次数据成功')
}
/**
* 选择对应的字幕文件
*/
async function SelectSrtFile() {
window.api.SelectFile(['srt'], (value) => {
if (value.code == 0) {
message.error(value.message)
return
}
bookTask.value.srtPath = value.value
})
}
/**
* 添加草稿
*/
async function AddJianyingDraft() {
let res = await window.book.AddJianyingDraft(bookTask.value.id, OperateBookType.BOOKTASK)
window.api.showGlobalMessageDialog(res)
/**
* 选择对应的配音文件
*/
async function SelectMusicFile() {
window.api.SelectFile(['mp3', 'wav'], (value) => {
if (value.code == 0) {
message.error(value.message)
return
}
bookTask.value.audioPath = value.value
})
}
return {
bookTask,
type,
AddJianyingDraft,
SelectSrtFile,
SelectMusicFile,
SaveVideoData,
UseBookVideoDataToBookTask,
backgroundMusicOptions,
rules: {
srtPath: [
{ required: true, message: '请选择背景音乐', trigger: ['input', 'blur', 'change'] }
],
audioPath: [
{ required: true, message: '请选择音频文件', trigger: ['input', 'blur', 'change'] }
]
}
}
/**
* 应用主小说相关数据
*/
async function UseBookVideoDataToBookTask() {
if (type.value == 'book') {
message.error('当前状态这个按钮不可用')
return
}
let res = await window.book.UseBookVideoDataToBookTask(
bookTask.value.id,
OperateBookType.BOOKTASK
)
if (res.code == 0) {
message.error(res.message)
} else {
// 将数据写回去
bookTask.value.backgroundMusic = res.data.backgroundMusic
bookTask.value.friendlyReminder = res.data.friendlyReminder
bookTask.value.draftSrtStyle = res.data.draftSrtStyle
bookTask.value.srtPath = res.data.srtPath
bookTask.value.audioPath = res.data.audioPath
message.success('应用主小说相关数据成功')
}
}
/**
* 保存数据
*/
async function SaveVideoData() {
console.log('SaveVideoData', bookTask.value)
if (props.type == 'book') {
let res = await window.db.UpdateBookData(bookTask.value.id, {
srtPath: bookTask.value.srtPath,
audioPath: bookTask.value.audioPath,
backgroundMusic: bookTask.value.backgroundMusic,
friendlyReminder: bookTask.value.friendlyReminder,
draftSrtStyle: bookTask.value.draftSrtStyle,
draftDepend: bookTask.value.draftDepend
})
if (res.code == 0) {
message.error(res.message)
} else {
message.success('保存小说数据成功')
}
} else if (props.type == 'bookTask') {
let res = await window.db.UpdateBookTaskData(bookTask.value.id, {
srtPath: bookTask.value.srtPath,
audioPath: bookTask.value.audioPath,
backgroundMusic: bookTask.value.backgroundMusic,
friendlyReminder: bookTask.value.friendlyReminder,
draftSrtStyle: bookTask.value.draftSrtStyle,
draftDepend: bookTask.value.draftDepend
})
if (res.code == 0) {
message.error(res.message)
} else {
message.success('保存小说批次数据成功')
}
} else {
message.error('未知的操作类型,请检查')
}
}
/**
* 添加草稿
*/
async function AddJianyingDraft() {
if (props.type == 'book') {
let res = await window.book.AddJianyingDraft(
props.selectBookTask,
OperateBookType.ASSIGNBOOKTASK
)
window.api.showGlobalMessageDialog(res)
} else if (props.type == 'bookTask') {
let res = await window.book.AddJianyingDraft(bookTask.value.id, OperateBookType.BOOKTASK)
window.api.showGlobalMessageDialog(res)
} else {
message.error('未知的操作类型,请检查')
return
}
}
let rules = ref({
srtPath: [{ required: true, message: '请选择背景音乐', trigger: ['input', 'blur', 'change'] }],
audioPath: [{ required: true, message: '请选择音频文件', trigger: ['input', 'blur', 'change'] }]
})
</script>
@@ -1,21 +1,21 @@
<template>
<div style="margin-bottom: 5px; margin-left: 5px; display: flex; align-items: center">
<n-button :render-icon="renderIcon" size="small" type="info" @click="AddBookDialog"
<n-button :render-icon="renderIcon" size="small" type="info" @click="AddBookDialog()"
>新增</n-button
>
<n-button style="margin-left: 5px" size="small" type="info" @click="HDImageAll"
<n-button style="margin-left: 5px" size="small" type="info" @click="HDImageAll()"
>一键高清</n-button
>
<n-button style="margin-left: 5px" type="info" size="small" @click="DraftAll"
<n-button style="margin-left: 5px" type="info" size="small" @click="DraftAll()"
>一键草稿</n-button
>
<n-button style="margin-left: 5px" type="info" size="small" @click="VideoAll"
<n-button style="margin-left: 5px" type="info" size="small" @click="VideoAll()"
>一键视频</n-button
>
<n-button style="margin-left: 5px" type="info" size="small" @click="ResetAll"
<n-button style="margin-left: 5px" type="info" size="small" @click="ResetAll()"
>一键重置</n-button
>
<n-button style="margin-left: 5px" type="info" size="small" @click="DeleteAll"
<n-button style="margin-left: 5px" type="info" size="small" @click="DeleteAll()"
>一键删除</n-button
>
</div>
@@ -26,11 +26,13 @@
:data="reverseManageStore.bookTaskData"
:scroll-x="800"
:row-props="rowProps"
:row-key="rowKey"
@update:checked-row-keys="handleCheck"
/>
</div>
</template>
<script>
<script setup>
import { ref, onMounted, defineComponent, onUnmounted, toRaw, watch, h } from 'vue'
import { useMessage, useDialog, NButton, NDataTable, NIcon, NWatermark } from 'naive-ui'
import { useReverseManageStore } from '../../../../stores/reverseManage'
@@ -42,198 +44,208 @@ import { OperateBookType } from '../../../../define/enum/bookEnum'
import { DEFINE_STRING } from '../../../../define/define_string'
import { ResponseMessageType } from '../../../../define/enum/softwareEnum'
import AddBookTask from './Components/ManageBook/AddBookTask.vue'
import ManageBookTaskGenerateInformation from './Components/ManageBook/ManageBookTaskGenerateInformation.vue'
export default defineComponent({
components: {
NButton,
NDataTable,
BookTaskListAction,
NWatermark
},
let reverseManageStore = useReverseManageStore()
let softwareStore = useSoftwareStore()
let dialog = useDialog()
const router = useRouter()
let message = useMessage()
let columns = createColumns()
const checkedRowKeysRef = ref([])
onMounted(async () => {
window.api.setEventListen([DEFINE_STRING.BOOK.MAIN_DATA_RETURN], (value) => {
if (value.code == 0) {
message.error(value.message)
return
}
if (value.type == ResponseMessageType.HD_IMAGE) {
softwareStore.spin.tip = `正在高清中 ${value.data.current} / ${value.data.total}`
}
})
})
setup() {
let reverseManageStore = useReverseManageStore()
let softwareStore = useSoftwareStore()
let dialog = useDialog()
const router = useRouter()
let message = useMessage()
onMounted(async () => {
window.api.setEventListen([DEFINE_STRING.BOOK.MAIN_DATA_RETURN], (value) => {
if (value.code == 0) {
message.error(value.message)
return
}
if (value.type == ResponseMessageType.HD_IMAGE) {
softwareStore.spin.tip = `正在高清中 ${value.data.current} / ${value.data.total}`
}
})
onUnmounted(() => {
window.api.removeEventListen([DEFINE_STRING.BOOK.MAIN_DATA_RETURN])
})
function rowKey(row) {
return row.id
}
function handleCheck(rowKeys) {
checkedRowKeysRef.value = rowKeys
}
function createColumns() {
return [
{
type: 'selection'
},
{
title: 'No.',
key: 'no',
width: 80
},
{
title: '名称',
key: 'name',
width: 130
},
{
title: '风格',
key: 'styleList'
},
{
title: '前缀',
key: 'prefix',
width: 130
},
{
title: '状态',
key: 'status',
width: 100
},
{
title: '操作',
key: 'action',
width: 215,
fixed: 'right',
render(row, index) {
return h(BookTaskListAction, {
bookTask: row
})
}
}
]
}
/**
* 高清数据
*/
async function hdImageFunc(id, operateBookType) {
softwareStore.spin.spinning = true
softwareStore.spin.tip = '正在高清中。。。'
let res = await window.book.HDImage(id, 4, operateBookType)
softwareStore.spin.spinning = false
if (res.code == 1) {
message.success('高清成功')
} else {
message.error(res.message)
}
}
/**
* 一键高清全部
*/
async function HDImageAll() {
console.log('一键高清', checkedRowKeysRef.value)
if (checkedRowKeysRef.value.length == 0) {
message.error('请选择要高清的数据')
return
}
softwareStore.spin.spinning = true
softwareStore.spin.tip = '正在进行高清检查。。。'
let checkImage = await window.book.CheckImageFileSize(
[...checkedRowKeysRef.value],
10240,
OperateBookType.ASSIGNBOOKTASK
)
softwareStore.spin.spinning = false
if (checkImage.code == 0) {
message.error(checkImage.message)
return
}
// 高清检查完成
if (checkImage.data && checkImage.data.length > 0) {
// 出现了图片大的,用户判断是不是需要高清
let msg = checkImage.data.map((item, index) => {
return item.outImagePath + '\n'
})
onUnmounted(() => {
window.api.removeEventListen([DEFINE_STRING.BOOK.MAIN_DATA_RETURN])
dialog.warning({
title: '高清警告',
content: '下面的图片大于10MB,是否继续高清?' + '\n' + msg,
positiveText: '确定',
negativeText: '取消',
onPositiveClick: async () => {
alert('确认高清')
await hdImageFunc([...checkedRowKeysRef.value], OperateBookType.ASSIGNBOOKTASK)
}
})
} else {
// 没有就直接高清
await hdImageFunc([...checkedRowKeysRef.value], OperateBookType.ASSIGNBOOKTASK)
}
}
function createColumns() {
return [
{
title: 'No.',
key: 'no',
width: 80
},
{
title: '名称',
key: 'name',
width: 130
},
{
title: '风格',
key: 'styleList'
},
{
title: '前缀',
key: 'prefix',
width: 130
},
{
title: '状态',
key: 'status',
width: 100
},
{
title: '操作',
key: 'action',
width: 215,
fixed: 'right',
render(row, index) {
return h(BookTaskListAction, {
bookTask: row
})
}
}
]
}
async function AddBookDialog() {
message.info('新增' + reverseManageStore.selectBook.id)
dialog.create({
title: '新增小说批次任务',
showIcon: false,
content: () => h(AddBookTask),
style: { width: '600px' }
})
}
/**
* 高清数据
*/
async function hdImageFunc(id, operateBookType) {
softwareStore.spin.spinning = true
softwareStore.spin.tip = '正在高清中。。。'
let res = await window.book.HDImage(id, 4, operateBookType)
softwareStore.spin.spinning = false
if (res.code == 1) {
message.success('高清成功')
} else {
message.error(res.message)
}
}
/**
* 一键高清全部
*/
async function HDImageAll() {
alert('高清全部')
softwareStore.spin.spinning = true
softwareStore.spin.tip = '正在进行高清检查。。。'
let checkImage = await window.book.CheckImageFileSize(
reverseManageStore.selectBook.id,
10240,
OperateBookType.BOOK
)
softwareStore.spin.spinning = false
if (checkImage.code == 0) {
message.error(checkImage.message)
return
}
// 高清检查完成
if (checkImage.data && checkImage.data.length > 0) {
// 出现了图片大的,用户判断是不是需要高清
let msg = checkImage.data.map((item, index) => {
return item.outImagePath + '\n'
})
dialog.warning({
title: '高清警告',
content: '下面的图片大于10MB,是否继续高清?' + '\n' + msg,
positiveText: '确定',
negativeText: '取消',
onPositiveClick: async () => {
alert('确认高清')
await hdImageFunc(reverseManageStore.selectBook.id, OperateBookType.BOOK)
}
})
} else {
// 没有就直接高清
await hdImageFunc(reverseManageStore.selectBook.id, OperateBookType.BOOK)
}
}
async function AddBookDialog() {
message.info('新增' + reverseManageStore.selectBook.id)
dialog.create({
title: '新增小说批次任务',
showIcon: false,
content: () => h(AddBookTask),
style: { width: '600px' }
/**
* 一键生成草稿
*/
async function DraftAll() {
if (checkedRowKeysRef.value.length == 0) {
message.error('请选择要生成草稿的任务')
return
}
// 草稿弹窗
dialog.info({
closeOnEsc: false,
title: `生成草稿前检查 ${reverseManageStore.selectBook.name}`,
maskClosable: false,
content: () =>
h(ManageBookTaskGenerateInformation, {
bookTask: reverseManageStore.selectBook,
type: 'book',
selectBookTask: [...checkedRowKeysRef.value]
})
}
})
}
/**
* 一键生成草稿
*/
async function DraftAll() {
alert('草稿全部')
}
/**
* 一键生成视频
*/
async function VideoAll() {
alert('视频全部')
}
/**
* 一键生成视频
*/
async function VideoAll() {
alert('视频全部')
}
/**
* 一键重置
*/
async function ResetAll() {
alert('重置全部')
}
/**
* 一键重置
*/
async function ResetAll() {
alert('重置全部')
}
/**
* 一键删除
*/
async function DeleteAll() {
alert('删除全部')
}
return {
reverseManageStore,
AddBookDialog,
HDImageAll,
DraftAll,
VideoAll,
ResetAll,
DeleteAll,
columns: createColumns(),
renderIcon() {
return h(NIcon, null, {
default: () => h(AddSharp, { size: '40', color: 'white' }, {})
})
},
rowProps: (row) => {
return {
style: 'cursor: pointer;',
onClick: async () => {
// message.info(row.id)
reverseManageStore.selectBookTask = row
softwareStore.spin.spinning = true
softwareStore.spin.tip = '正在加载数据'
// 跳转
router.push({ name: 'manage_book', params: { id: row.id } })
}
}
}
/**
* 一键删除
*/
async function DeleteAll() {
alert('删除全部')
}
const renderIcon = () => {
return h(NIcon, null, {
default: () => h(AddSharp, { size: '40', color: 'white' }, {})
})
}
const rowProps = (row) => {
return {
style: 'cursor: pointer;',
ondblclick: async () => {
// message.info(row.id)
reverseManageStore.selectBookTask = row
softwareStore.spin.spinning = true
softwareStore.spin.tip = '正在加载数据'
// 跳转
router.push({ name: 'manage_book', params: { id: row.id } })
}
}
})
}
</script>
@@ -1,7 +1,7 @@
<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%">
<n-split v-else direction="horizontal" :min="0.4" :max="0.8" :default-size="0.4" height="100%">
<template #1> <ManageBook style="height: 100%" /> </template>
<template #2>
<ManageBookTask style="height: 100%" />
@@ -46,14 +46,24 @@
<template #unchecked> </template>
</n-switch>
</n-form-item>
<n-form-item label="人物场景选择模式" style="margin-left: 20px">
<n-form-item label="选择高清倍率" style="margin-left: 20px">
<n-select
size="small"
placeholder="请选择"
:options="hdSelectOptions"
v-model:value="formValue.hdScale"
style="width: 120px"
/>
</n-form-item>
<n-form-item style="margin-left: 20px" label="人物场景选择模式">
<n-select
size="small"
placeholder="请选择"
:options="character_select_model_options"
v-model:value="formValue.character_select_model"
style="width: 120px"
/>
>
</n-select>
</n-form-item>
<n-form-item style="margin-left: 20px"
><n-checkbox v-model:checked="formValue.window_wh_bm_remember"
@@ -212,12 +222,27 @@ export default defineComponent({
theme: softwareStore.globalSetting.theme,
character_select_model: window.config.character_select_model,
window_wh_bm_remember: window.config.window_wh_bm_remember,
laiApiSelect: window.config.laiApiSelect ? window.config.laiApiSelect : LaiAPIType.MAIN
laiApiSelect: window.config.laiApiSelect ? window.config.laiApiSelect : LaiAPIType.MAIN,
hdScale: window.config.hdScale ?? 2
})
let show = ref(false)
let gpt_options = ref([])
let gpt_model_options = ref([])
let character_select_model_options = ref([])
let hdSelectOptions = ref([
{
label: '2倍',
value: 2
},
{
label: '3倍',
value: 3
},
{
label: '4倍',
value: 4
}
])
let dialog = useDialog()
let loading = ref(false)
/**
@@ -472,6 +497,7 @@ export default defineComponent({
AddGptPrompt,
character_select_model_options,
softwareStore,
hdSelectOptions,
ModifyTranslateSetting,
laiApiOptions: [
{