V 3.2.1 2024.11.9

1. (聚合推文)修复原创默认出图方式设置默认值
2. (聚合推文)优化出图显示
3. (聚合推文)添加图片上传功能,包括主图和选图区域
4. (聚合推文)新增图片缓存区,上传缓存图片(主图和选图区的图片),可以直接在当前小说所有的批次中的分镜中调用(下载到主图和选图区)
5. (聚合推文)添加一键修脸开关
6. (聚合推文)原创添加一键锁定
7. (聚合推文)新增小说批次任务显示当前所属小说
8. (聚合推文)小说批次任务状态显示优化
9. (聚合推文)优化后台任务状态显示
10. (聚合推文)原创,反推 一键生图 修复
This commit is contained in:
2024-11-09 16:46:06 +08:00
parent 51deef0c09
commit 6fa58e4d94
69 changed files with 1865 additions and 274 deletions
+11 -8
View File
@@ -6,11 +6,13 @@
:theme="softwareStore.globalSetting.theme == 'dark' ? darkTheme : null"
>
<n-message-provider>
<n-dialog-provider>
<n-notification-provider>
<RouterView></RouterView>
</n-notification-provider>
</n-dialog-provider>
<n-modal-provider>
<n-dialog-provider>
<n-notification-provider>
<RouterView></RouterView>
</n-notification-provider>
</n-dialog-provider>
</n-modal-provider>
</n-message-provider>
</n-config-provider>
</n-spin>
@@ -24,6 +26,7 @@ import {
NMessageProvider,
NDialogProvider,
NConfigProvider,
NModalProvider,
darkTheme,
NNotificationProvider,
NSpin
@@ -38,13 +41,13 @@ export default defineComponent({
NDialogProvider,
NMessageProvider,
NNotificationProvider,
NModalProvider,
NSpin
},
setup() {
let softwareStore = useSoftwareStore()
onMounted(async () => {
softwareStore.SoftColor = SoftColor
window.api.getSettingDafultData(async (value) => {
await window.darkMode.toggle(value.theme)
@@ -80,8 +83,8 @@ export default defineComponent({
/* Customize the scrollbar */
::-webkit-scrollbar {
width: 2px;
height: 4px;
width: 4px;
height: 6px;
}
/* Track */
@@ -103,6 +103,7 @@ import {
NFormItem,
NInput,
NButton,
NTag,
NGrid,
NGridItem,
NSelect
@@ -144,7 +145,10 @@ let columns = [
{
title: '状态',
key: 'status',
minWidth: 100
minWidth: 100,
render: (row) => {
return renderStatus(row)
}
},
{
title: '失败原因',
@@ -156,6 +160,14 @@ let columns = [
}
]
function renderStatus(row) {
return h(
NTag,
{ bordered: false, type: GetBookBackTaskStatusLabel(row.status).type },
{ default: GetBookBackTaskStatusLabel(row.status).label }
)
}
async function ResetQuery() {
softwareStore.ResetBackTaskQueryData()
await query(1, pagination.value.pageSize)
@@ -237,7 +249,7 @@ let GeBookBackTaskStatus = () => {
let options = []
for (const key in BookBackTaskStatus) {
options.push({
label: GetBookBackTaskStatusLabel(BookBackTaskStatus[key]),
label: GetBookBackTaskStatusLabel(BookBackTaskStatus[key]).label,
value: BookBackTaskStatus[key]
})
}
@@ -0,0 +1,300 @@
<template>
<n-spin :show="show">
<n-collapse
id="l-collapse"
v-model:expanded-names="defaultExpandedNames"
@item-header-click="handleItemHeaderClick"
>
<n-collapse-item
v-for="(item, index) in data"
:title="item.bookTaskName"
:name="item.bookTaskId"
:key="item.bookTaskId"
>
<n-image-group>
<div
style="
display: flex;
flex-wrap: wrap;
align-items: center;
padding-left: 10px;
min-width: 50px;
overflow: auto;
"
>
<div
v-for="(image, index) in item.imagePaths"
:key="image.id"
:id="image.id"
class="image-container"
@click="SelectImage(image, index)"
>
<n-image
:width="150"
style="margin: 5px"
:src="image.imagePath"
alt="图片描述"
preview-disabled
lazy
>
</n-image>
</div>
</div>
</n-image-group>
</n-collapse-item>
</n-collapse>
<div style="margin-top: 15px; display: flex; justify-content: flex-end">
<n-button type="info" @click="SaveImageToData">选择完成</n-button>
</div>
<template #description> 加载数据中 </template>
</n-spin>
</template>
<script setup>
import { onMounted, ref } from 'vue'
import { NImageGroup, NImage, NSpin, NButton, useMessage, NCollapse, NCollapseItem } from 'naive-ui'
import { useReverseManageStore } from '@/stores/reverseManage'
import { v4 as uuidv4 } from 'uuid'
import { MJImageType } from '@/define/enum/mjEnum'
import { MJAction } from '@/define/enum/bookEnum'
let reverseManageStore = useReverseManageStore()
let props = defineProps({
type: undefined,
bookTaskDetailId: undefined,
bookTaskId: undefined
})
let message = useMessage()
let data = ref([])
let show = ref(true)
let defaultExpandedNames = ref([])
let selectImageIds = ref([])
onMounted(async () => {
try {
// 加载所有的小说批次的数据
let res = await window.book.GetAllBookTaskImageCache(props.bookTaskId)
if (res.code == 0) {
message.error(res.message)
return
}
console.log('GetAllBookTaskImageCache', res.data)
// 将指定ID的数据放在最前面
const specifiedId = reverseManageStore.selectBookTask.id // 替换为你的指定ID
res.data.sort((a, b) =>
a.bookTaskId === specifiedId ? -1 : b.bookTaskId === specifiedId ? 1 : 0
)
res.data.forEach((item) => {
let images = []
for (let i = 0; i < item.imagePaths.length; i++) {
const element = item.imagePaths[i]
images.push({
id: uuidv4(),
imagePath: element
})
}
data.value.push({
...item,
imagePaths: images
})
})
defaultExpandedNames.value = res.data.map((item) => {
if (item.bookTaskId == specifiedId) {
return item.bookTaskId
}
})
message.success('加载数据成功')
let lCollapse = document.getElementById('l-collapse')
if (lCollapse) {
lCollapse.style.height = window.innerHeight - 150 + 'px'
lCollapse.style.overflow = 'auto'
}
} catch (error) {
message.error(error.message)
} finally {
show.value = false
}
})
async function handleItemHeaderClick({ name, expanded }) {
setTimeout(() => {
if (expanded) {
// 判断里面的数据是不是被选择,选择的话添加效果
let bookTasks = data.value.filter((item) => item.bookTaskId == name)
for (let i = 0; i < bookTasks.length; i++) {
const element = bookTasks[i]
for (let i = 0; i < element.imagePaths.length; i++) {
const image = element.imagePaths[i]
if (selectImageIds.value.some((x) => x.id == image.id)) {
let el = document.getElementById(image.id)
if (el) {
el.classList.add('selected')
}
}
}
}
}
}, 0)
}
async function SelectImage(image, index) {
if (props.type == 'outImagePath') {
// 选择单个图片
let tempSelectImageIds = selectImageIds.value
selectImageIds.value = []
for (let i = 0; i < tempSelectImageIds.length; i++) {
const element = tempSelectImageIds[i]
let el = document.getElementById(element.id)
if (el) {
el.classList.remove('selected')
}
}
selectImageIds.value.push(image)
for (let i = 0; i < selectImageIds.value.length; i++) {
const element = selectImageIds.value[i]
let el = document.getElementById(element.id)
if (el) {
el.classList.add('selected')
}
}
} else if (props.type == 'subImagePath') {
// 选择多个图片
// 判断当前点击的这个是不是被选中没有被选中就选中,选中的话,就取消选中给
let findIndex = selectImageIds.value.findIndex((x) => x.id == image.id)
if (findIndex == -1) {
selectImageIds.value.push(image)
for (let i = 0; i < selectImageIds.value.length; i++) {
const element = selectImageIds.value[i]
let el = document.getElementById(element.id)
if (el) {
el.classList.add('selected')
}
}
} else {
// 取消选中
// 删除选中的图片
selectImageIds.value.splice(findIndex, 1)
let el = document.getElementById(image.id)
if (el) {
el.classList.remove('selected')
}
}
}
}
function RemoveImageSelect() {
for (let i = 0; i < selectImageIds.value.length; i++) {
const element = selectImageIds.value[i]
let el = document.getElementById(element.id)
if (el) {
el.classList.remove('selected')
}
}
}
async function SaveImageToData() {
// 开始保存
if (selectImageIds.value.length <= 0) {
message.error('请选择图片')
return
}
let selectImagePaths = selectImageIds.value.map((x) => x.imagePath)
if (selectImagePaths.length <= 0) {
message.error('请选择图片')
return
}
if (props.type == 'outImagePath') {
// 主图
// 找到图片地址
let res = await window.book.SaveCacheImageToData(
props.bookTaskDetailId,
selectImagePaths[0],
props.type
)
console.log('SaveCacheImageToData', res)
if (res.code == 0) {
message.error(res.message)
return
}
// 保存成功
let findIndex = reverseManageStore.selectBookTaskDetail.findIndex(
(x) => x.id == props.bookTaskDetailId
)
if (findIndex != -1) {
reverseManageStore.selectBookTaskDetail[findIndex].outImagePath = res.data
reverseManageStore.selectBookTaskDetail[findIndex].mjMessage = {
progress: 100,
status: 'success',
category: MJImageType.IMPORT,
messageId: '',
action: MJAction.IMAGINE
}
}
RemoveImageSelect()
selectImageIds.value = []
message.success(res.message)
} else if (props.type == 'subImagePath') {
let res = await window.book.SaveCacheImageToData(
props.bookTaskDetailId,
selectImagePaths,
props.type
)
console.log('SaveCacheImageToData', res)
if (res.code == 0) {
message.error(res.message)
return
}
// 做一些修改数据的操作
let findIndex = reverseManageStore.selectBookTaskDetail.findIndex(
(item) => item.id == props.bookTaskDetailId
)
if (findIndex != -1) {
let subImagePath = reverseManageStore.selectBookTaskDetail[findIndex].subImagePath
subImagePath.push(...res.data)
reverseManageStore.selectBookTaskDetail[findIndex].subImagePath = subImagePath.map(
(item) => item.split('?t=')[0] + `?t=${new Date().getTime()}`
)
}
RemoveImageSelect()
selectImageIds.value = []
message.success(res.message)
}
}
</script>
<style scoped>
.image-container {
position: relative;
cursor: pointer;
margin: 5px 5px;
transition:
transform 0.3s,
box-shadow 0.3s;
}
.image-container.selected {
transform: scale(1.05);
box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.3);
border: 2px solid #1890ff;
}
.image-container::after {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0;
transition: opacity 0.3s;
}
.image-container.selected::after {
opacity: 1;
}
</style>
@@ -0,0 +1,119 @@
<template>
<div>
<n-image-group>
<div
style="
display: flex;
flex-wrap: wrap;
align-items: center;
padding-left: 10px;
min-width: 50px;
overflow: auto;
"
>
<div
v-for="(image, index) in data"
:key="image.id"
:id="image.id"
class="image-container"
:class="{ selected: image.selected }"
@click="SelectImage(image, index)"
>
<n-image
:width="150"
style="margin: 5px"
:src="image.imagePath"
alt="图片描述"
preview-disabled
lazy
>
</n-image>
</div>
</div>
</n-image-group>
<div>
<n-button type="info" @click="UpdateImageToCache">选择完成</n-button>
</div>
</div>
</template>
<script setup>
import { onMounted, ref } from 'vue'
import { NImage, NImageGroup, NButton, useMessage } from 'naive-ui'
import { v4 as uuidv4 } from 'uuid'
import { useReverseManageStore } from '@/stores/reverseManage'
let props = defineProps({
imageList: undefined
})
let data = ref([])
let message = useMessage()
let reverseManageStore = useReverseManageStore()
onMounted(() => {
for (let i = 0; i < props.imageList.length; i++) {
const element = props.imageList[i]
data.value.push({
id: uuidv4(),
imagePath: element,
selected: false
})
}
})
async function SelectImage(image, index) {
data.value[index].selected = !data.value[index].selected
}
async function UpdateImageToCache() {
let tempData = data.value.filter((item) => item.selected)
if (tempData.length <= 0) {
message.error('请选择图片')
return
}
let images = tempData.map((item) => item.imagePath)
let res = await window.book.UpLoadImageToCache(reverseManageStore.selectBookTask.id, images)
if (res.code == 1) {
// 将当前选中的全部删除
for (let i = 0; i < data.value.length; i++) {
const element = data.value[i]
if (element.selected) {
element.selected = false
}
}
}
window.api.showGlobalMessage(res)
}
</script>
<style scoped>
.image-container {
position: relative;
cursor: pointer;
margin: 5px 5px;
transition:
transform 0.3s,
box-shadow 0.3s;
}
.image-container.selected {
transform: scale(1.05);
box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.3);
border: 2px solid #1890ff;
}
.image-container::after {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0;
transition: opacity 0.3s;
}
.image-container.selected::after {
opacity: 1;
}
</style>
@@ -0,0 +1,101 @@
<template>
<div style="display: flex; align-items: center">
<span>参数</span>
<n-dropdown
trigger="hover"
:options="options"
@select="handleSelect"
:render-option="renderOption"
>
<n-button text :style="style">
<n-icon> <MenuOpenRound /> </n-icon
></n-button>
</n-dropdown>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { NDropdown, NButton, NIcon, useMessage } from 'naive-ui'
import MenuOpenRound from '@/renderer/src/components/Icon/MenuOpenRound.vue'
import { useReverseManageStore } from '@/stores/reverseManage'
import { BookImageCategory } from '@/define/enum/bookEnum'
import { useSoftwareStore } from '@/stores/software'
import { TimeDelay } from '@/define/Tools/time'
let props = defineProps({
style: undefined
})
let style = ref(props.style)
let message = useMessage()
let reverseManageStore = useReverseManageStore()
let softwareStore = useSoftwareStore()
let options = [
{ label: '启用修脸', key: 'openFaceRepair' },
{ label: '关闭修脸', key: 'closeFaceRepair' }
]
async function ModifyFaceRepair(key) {
//adetailer
let adetailer = true
if (key == 'openFaceRepair') {
adetailer = true
} else if (key == 'closeFaceRepair') {
adetailer = false
} else {
message.error('ModifyFaceRepair' + '_' + '未知操作')
}
// 开始修改
for (let i = 0; i < reverseManageStore.selectBookTaskDetail.length; i++) {
const element = reverseManageStore.selectBookTaskDetail[i]
let res = await window.db.UpdateBookTaskDetailData(element.id, {
adetailer: adetailer
})
if (res.code == 1) {
let findIndex = reverseManageStore.selectBookTaskDetail.findIndex(
(item) => item.id == element.id
)
reverseManageStore.selectBookTaskDetail[findIndex].adetailer = adetailer
} else {
throw new Error(`修改${element.name}失败`)
}
}
await TimeDelay(1000)
}
async function handleSelect(key) {
softwareStore.spin.spinning = true
softwareStore.spin.tip = '正在修改所有的修脸参数'
try {
switch (key) {
case 'openFaceRepair':
await ModifyFaceRepair(key)
break
case 'closeFaceRepair':
await ModifyFaceRepair(key)
break
default:
message.error('未知操作')
break
}
} catch (error) {
message.error('操作失败,' + error.message)
} finally {
softwareStore.spin.spinning = false
}
}
function renderOption({ node, option }) {
if (option.key === 'openFaceRepair' || option.key === 'closeFaceRepair') {
if (
reverseManageStore.selectBookTask.imageCategory == BookImageCategory.SD ||
reverseManageStore.selectBookTask.imageCategory == BookImageCategory.FLUX_FORGE
) {
return node
}
} else {
return node
}
}
</script>
@@ -50,7 +50,21 @@
@drop="imageDragDrop"
@dragover="imageDragOver"
>
<div style="display: flex; align-items: center; position: relative">
<div
style="display: flex; align-items: center; position: relative"
@contextmenu="handleContextMenu"
>
<n-button
text
:type="data.imageLock ? 'error' : 'primary'"
style="font-size: 32px; position: absolute; left: 0px; top: 0px"
@click="ModifyLock"
>
<n-icon>
<LockClosed v-if="data.imageLock" />
<LockOpen v-else />
</n-icon>
</n-button>
<n-image
class="g-image-class generate-image-show"
:src="data.outImagePath ? data.outImagePath : softwareStore.globalSetting.space_image"
@@ -59,33 +73,69 @@
:height="120"
lazy
/>
<n-button
text
:type="data.imageLock ? 'error' : 'primary'"
style="font-size: 24px; position: absolute; left: -12px; top: -5px"
@click="ModifyLock"
>
<n-icon>
<LockClosed v-if="data.imageLock" />
<LockOpen v-else />
</n-icon>
</n-button>
<n-button
text
type="info"
style="font-size: 24px; position: absolute; left: 8px; top: -5px"
@click="DownloadImage"
v-if="reverseManageStore.selectBookTask.imageCategory == 'mj'"
>
<n-icon>
<Download />
</n-icon>
</n-button>
</div>
<n-dropdown
:options="mainImageOptions"
placement="bottom-start"
trigger="manual"
:x="x"
:y="y"
:show="showDropdown"
:on-clickoutside="onClickoutside"
@select="handleSelect"
>
</n-dropdown>
<div>
<n-divider vertical style="height: 100%" />
</div>
<div style="display: flex; align-items: center">
<div style="display: flex">
<div style="width: 24px">
<n-tooltip>
<template #trigger>
<n-button
style="font-size: 24px"
text
color="#ee7959"
@click="UpLoadImageToSelecImageRegion"
>
<n-icon>
<UploadRound />
</n-icon>
</n-button>
</template>
上传本地图片到选图区
</n-tooltip>
<n-tooltip>
<template #trigger>
<n-button
style="font-size: 24px"
text
color="#e5a84b"
@click="UpLoadImageRegionToCache"
>
<n-icon>
<OpenInBrowserRound />
</n-icon>
</n-button>
</template>
上传选图区图片到缓存区
</n-tooltip>
<n-tooltip>
<template #trigger>
<n-button
style="font-size: 24px"
text
color="#45465e"
@click="DownloadCacheImageToSelecImageRegion"
>
<n-icon>
<DownloadRound />
</n-icon>
</n-button>
</template>
从缓存区下载图片到选图区
</n-tooltip>
</div>
<n-image-group>
<div
style="
@@ -100,7 +150,7 @@
subImage="true"
class="g-image-class"
draggable="true"
:width="56"
:width="55"
style="margin: 1px"
v-for="(image, index) in data.subImagePath"
:key="image.id"
@@ -113,11 +163,21 @@
</n-image-group>
</div>
</div>
<n-drawer v-model:show="showDrawer" :width="drawerWidth" placement="left">
<n-drawer-content :title="drawerTitle">
<BookTaskImageCache
:type="drawertype"
:bookTaskDetailId="data.id"
:bookTaskId="reverseManageStore.selectBookTask.id"
/>
</n-drawer-content>
</n-drawer>
</div>
</template>
<script setup>
import { ref, onMounted, toRaw, watch } from 'vue'
import { ref, onMounted, nextTick, watch, h } from 'vue'
import {
NImage,
useDialog,
@@ -127,14 +187,25 @@ import {
NButton,
NPopover,
NTag,
useMessage
NDropdown,
NDrawer,
NTooltip,
NDrawerContent,
useMessage,
useModal
} from 'naive-ui'
import { LockClosed, LockOpen, Download } from '@vicons/ionicons5'
import { LockClosed, LockOpen, Download, FolderOpen } from '@vicons/ionicons5'
import UploadRound from '@/renderer/src/components/Icon/UploadRound.vue'
import { useSoftwareStore } from '../../../../../stores/software'
import { useReverseManageStore } from '../../../../../stores/reverseManage'
import { useImageStore } from '../../../../../stores/image'
import { BookImageCategory, OperateBookType } from '../../../../../define/enum/bookEnum'
import { isEmpty } from 'lodash'
import OpenInBrowserRound from '@/renderer/src/components/Icon/OpenInBrowserRound.vue'
import BookTaskImageCache from '@/renderer/src/components/Book/Components/Image/BookTaskImageCache.vue'
import DownloadRound from '@/renderer/src/components/Icon/DownloadRound.vue'
import SelectRegionImage from '@/renderer/src/components/Book/Components/Image/SelectRegionImage.vue'
import { isEmpty, reverse } from 'lodash'
import { MJAction, MJImageType } from '@/define/enum/mjEnum'
let props = defineProps({
initData: undefined,
index: undefined
@@ -142,6 +213,7 @@ let props = defineProps({
let imageStore = useImageStore()
let message = useMessage()
let dialog = useDialog()
let modal = useModal()
let data = ref(props.initData)
let images = ref(props.initData.subImagePath)
let outImagePath = ref(props.initData.outImagePath)
@@ -149,6 +221,12 @@ let width = ref(null)
let dragTarget = null
let reverseManageStore = useReverseManageStore()
let softwareStore = useSoftwareStore()
let showDropdown = ref(false)
let showDrawer = ref(false)
let drawertype = ref('outImagePath')
let drawerTitle = ref(
`选择缓存区文件__主图__${reverseManageStore.selectBookTask.name}__${props.initData.name}`
)
// 监听 props.initData.subImagePath 修改
watch(
@@ -165,7 +243,7 @@ watch(
() => props.initData.outImagePath,
(value) => {
if (value) {
outImagePath.value = value + `?t=${new Date().getTime()}`
outImagePath.value = value.split('?t=')[0] + `?t=${new Date().getTime()}`
}
}
)
@@ -250,7 +328,6 @@ async function imageDragOver(e) {
}
async function ModifyLock() {
if (!data.value.imageLock) {
// 锁定之前,判断是不是有
if (!outImagePath.value) {
@@ -335,4 +412,237 @@ async function DownloadImage() {
}
})
}
/** 上传图片信息到小说出图中 */
async function UpLoadImageToBookAndUpdateMessage() {
dialog.warning({
title: '上传图片提示',
content:
'注意:上传的图片(png)到主图,并且会覆盖原有的图片,不可恢复,上传到图片只能是裁剪过的,该操作不会自动裁剪上传,是否继续?',
positiveText: '继续',
negativeText: '取消',
onPositiveClick: async () => {
// 弹窗选择图片
let imageFiles = await window.system.SelectSingleFile(['png'])
if (imageFiles.code == 0) {
message.error(imageFiles.message)
return
}
let res = await window.book.UpLoadImageToBookAndUpdateMessage(
data.value.id,
imageFiles.data,
'outImagePath'
)
if (res.code == 1) {
// 做一些修改数据的操作
let findIndex = reverseManageStore.selectBookTaskDetail.findIndex(
(item) => item.id == data.value.id
)
if (findIndex != -1) {
reverseManageStore.selectBookTaskDetail[findIndex].outImagePath = res.data
reverseManageStore.selectBookTaskDetail[findIndex].mjMessage = {
progress: 100,
status: 'success',
category: MJImageType.IMPORT,
messageId: '',
action: MJAction.IMAGINE
}
}
}
window.api.showGlobalMessage(res)
}
})
}
/** 大小当前小说批次的出图文件夹 */
async function OpenBookTaskDetailImageFolder() {
let imageFolder = reverseManageStore.selectBookTask.imageFolder
let res = await window.system.OpenFolder({
folderPath: imageFolder,
baseProject: false
})
if (res.code == 0) {
message.error(res.message)
} else {
message.success('打开文件夹成功')
}
}
/** 将图片上传到选图区域 */
async function UpLoadImageToSelecImageRegion() {
let da = dialog.warning({
title: '上传图片提示',
content:
'注意:将选中的图片(png)上传到选图区域,回叠加到后面,上传到图片只能是裁剪过的,该操作不会自动裁剪上传,是否继续?',
positiveText: '继续',
negativeText: '取消',
onPositiveClick: async () => {
// 弹窗选择图片
let imageFiles = await window.system.SelectMultipleFile(['png'])
if (imageFiles.code == 0) {
message.error(imageFiles.message)
return
}
let res = await window.book.UpLoadImageToBookAndUpdateMessage(
data.value.id,
imageFiles.data,
'subImagePath'
)
if (res.code == 1) {
// 做一些修改数据的操作
let findIndex = reverseManageStore.selectBookTaskDetail.findIndex(
(item) => item.id == data.value.id
)
debugger
if (findIndex != -1) {
let subImagePath = reverseManageStore.selectBookTaskDetail[findIndex].subImagePath
subImagePath.push(...res.data)
reverseManageStore.selectBookTaskDetail[findIndex].subImagePath = subImagePath.map(
(item) => item.split('?t=')[0] + `?t=${new Date().getTime()}`
)
}
}
window.api.showGlobalMessage(res)
}
})
}
async function UpLoadImageRegionToCache() {
if (data.value.subImagePath.length <= 0) {
message.error('没有选图区图片,不能上传到缓存区')
return
}
dialog.create({
title: '上传图片到缓存区',
showIcon: false,
style: 'width: 800px',
content: () =>
h(SelectRegionImage, {
imageList: data.value.subImagePath
})
})
}
async function DownloadCacheImageToSelecImageRegion() {
drawertype.value = 'subImagePath'
drawerTitle.value = `选择缓存区文件__选图区__${reverseManageStore.selectBookTask.name}__${data.value.name}`
showDrawer.value = true
}
function renderIcon(icon) {
return () => {
return h(
NIcon,
{
size: 18
},
{
default: () => h(icon)
}
)
}
}
let mainImageOptions = []
function GetMainImageOptions() {
let t = [
{
label: data.value.imageLock ? '解锁' : '锁定',
key: 'lock',
icon: data.value.imageLock ? renderIcon(LockClosed) : renderIcon(LockOpen)
},
{
label: '下载图片',
key: 'download',
icon: renderIcon(Download)
},
{
label: '上传图片到小说',
key: 'upload',
icon: renderIcon(UploadRound)
},
{
label: '上传图片到缓存区',
key: 'uploadToCache',
icon: renderIcon(OpenInBrowserRound)
},
{
label: '从缓存区下载',
key: 'downloadFromCache',
icon: renderIcon(DownloadRound)
},
{
label: '打开文件夹',
key: 'open',
icon: renderIcon(FolderOpen)
}
]
if (reverseManageStore.selectBookTask.imageCategory != BookImageCategory.MJ) {
return t.filter((item) => item.key != 'download')
} else {
return t
}
}
let x = ref(0)
let y = ref(0)
function handleContextMenu(e) {
e.preventDefault()
showDropdown.value = false
nextTick().then(() => {
mainImageOptions = GetMainImageOptions()
showDropdown.value = true
x.value = e.clientX
y.value = e.clientY
})
}
function onClickoutside() {
showDropdown.value = false
}
async function UpLoadImageToCache() {
if (isEmpty(data.value.outImagePath)) {
message.error('没有生成图片,不能上传到缓存区')
return
}
let da = dialog.warning({
title: '上传缓存区提示',
content: '会将当前主题上传到缓存区,缓存区的图片可以在其他地方使用,是否继续?',
positiveText: '继续',
negativeText: '取消',
onPositiveClick: async () => {
let res = await window.book.UpLoadImageToCache(
reverseManageStore.selectBookTask.id,
data.value.outImagePath
)
window.api.showGlobalMessage(res)
da.destroy()
}
})
}
let drawerWidth = ref(window.innerWidth * 0.8)
async function DownloadImageFromCache() {
drawertype.value = 'outImagePath'
showDrawer.value = true
}
async function handleSelect(key) {
showDropdown.value = false
if (key == 'lock') {
await ModifyLock()
} else if (key == 'download') {
await DownloadImage()
} else if (key == 'upload') {
await UpLoadImageToBookAndUpdateMessage()
} else if (key == 'open') {
await OpenBookTaskDetailImageFolder()
} else if (key == 'uploadToCache') {
await UpLoadImageToCache()
} else if (key == 'downloadFromCache') {
await DownloadImageFromCache()
} else {
message.error('未知操作')
}
}
</script>
@@ -43,7 +43,7 @@ import { NSelect, NButton, useMessage, useDialog, NPopover, NIcon } from 'naive-
import { useSoftwareStore } from '../../../../../stores/software'
import { useReverseManageStore } from '../../../../../stores/reverseManage'
import { Download } from '@vicons/ionicons5'
import { OperateBookType } from '../../../../../define/enum/bookEnum'
import { BookImageCategory, OperateBookType } from '../../../../../define/enum/bookEnum'
let softwareStore = useSoftwareStore()
let message = useMessage()
let dialog = useDialog()
@@ -53,7 +53,7 @@ let image_options = ref([])
let select = computed(() =>
reverseManageStore.selectBookTask.imageCategory
? reverseManageStore.selectBookTask.imageCategory
: softwareStore.globalSetting.defaultImageMode
: softwareStore.globalSetting.defaultImageMode ?? BookImageCategory.MJ
)
onMounted(async () => {
@@ -8,132 +8,188 @@
@update:value="handleUpdateValue"
:options="options"
/>
<n-dropdown trigger="hover" :options="blockOptions" @select="ImageLockOperation">
<n-button
:color="softwareStore.SoftColor.ZHUYANTUO"
@click="ImageLockOperation('lock')"
size="tiny"
style="margin-left: 5px"
>一键锁定</n-button
>
</n-dropdown>
<n-button
:color="softwareStore.SoftColor.ZHUYANTUO"
@click="OneToFourBookTask"
size="tiny"
style="margin-left: 5px"
>一拆四</n-button
<n-dropdown
trigger="hover"
:options="blockOptions"
@select="dropdownSelectHandle"
:render-option="renderOptionHandle"
>
<n-button text :style="style">
<n-icon> <MenuOpenRound /> </n-icon>
</n-button>
</n-dropdown>
</div>
</template>
<script>
import { ref, onMounted, defineComponent, onUnmounted, toRaw, watch, computed } from 'vue'
import { useMessage, useDialog, NSelect, NButton, NDropdown } from 'naive-ui'
<script setup>
import { ref, onMounted, computed, render } from 'vue'
import { useMessage, useDialog, NIcon, NSelect, NButton, NDropdown } from 'naive-ui'
import { BookImageCategory, OperateBookType } from '../../../../../define/enum/bookEnum'
import { useReverseManageStore } from '../../../../../stores/reverseManage'
import { useSoftwareStore } from '../../../../../stores/software'
import MenuOpenRound from '../../Icon/MenuOpenRound.vue'
export default defineComponent({
components: { NSelect, NButton, NDropdown },
let props = defineProps({
style: undefined
})
let style = ref(props.style)
setup() {
let message = useMessage()
let dialog = useDialog()
let softwareStore = useSoftwareStore()
let reverseManageStore = useReverseManageStore()
let select = computed(() =>
reverseManageStore.selectBookTask.imageCategory
? reverseManageStore.selectBookTask.imageCategory
: softwareStore.globalSetting.defaultImageMode
)
let options = ref([])
let message = useMessage()
let dialog = useDialog()
let softwareStore = useSoftwareStore()
let reverseManageStore = useReverseManageStore()
let select = computed(() =>
reverseManageStore.selectBookTask.imageCategory
? reverseManageStore.selectBookTask.imageCategory
: softwareStore.globalSetting.defaultImageMode ?? BookImageCategory.MJ
)
let options = ref([])
onMounted(async () => {
debugger
// 获取生图下拉列表的方式
await window.api.GetImageGenerateCategory((value) => {
if (value.code == 0) {
message.error(value.message)
return
}
options.value = value.data
})
})
async function handleUpdateValue(value) {
// 将值的修改保存进数据库中
let res = await window.db.UpdateBookTaskData(reverseManageStore.selectBookTask.id, {
imageCategory: value
})
if (res.code == 0) {
message.error(res.message)
return
}
reverseManageStore.selectBookTask.imageCategory = value
message.success('修改成功')
onMounted(async () => {
// 获取生图下拉列表的方式
await window.api.GetImageGenerateCategory((value) => {
if (value.code == 0) {
message.error(value.message)
return
}
options.value = value.data
})
})
/**
* 土拍你
* @param value
*/
async function ImageLockOperation(value) {
let res = await window.book.ImageLockOperation(
async function handleUpdateValue(value) {
// 将值的修改保存进数据库中
let res = await window.db.UpdateBookTaskData(reverseManageStore.selectBookTask.id, {
imageCategory: value
})
if (res.code == 0) {
message.error(res.message)
return
}
reverseManageStore.selectBookTask.imageCategory = value
message.success('修改成功')
}
async function ImageLockOperation(value) {
let res = await window.book.ImageLockOperation(
reverseManageStore.selectBookTask.id,
value,
OperateBookType.BOOKTASK
)
if (res.code == 0) {
message.error(res.message)
return
}
for (let i = 0; i < res.data.length; i++) {
const element = res.data[i]
let index = reverseManageStore.selectBookTaskDetail.findIndex((item) => item.id == element.id)
if (index != -1) {
reverseManageStore.selectBookTaskDetail[index].imageLock = element.imageLock
}
}
message.success(res.message)
}
async function dropdownSelectHandle(key) {
switch (key) {
case 'lock':
case 'unlock':
await ImageLockOperation(key)
break
case 'downloadMJImage':
await DownloadAllImage()
break
case 'oneToFour':
await OneToFourBookTask()
break
default:
message.error('未知操作')
break
}
}
async function DownloadAllImage() {
let da = dialog.warning({
title: '采集所有图片提示',
content:
'即将开始采集所有的MJ生图图片,满足一下条件的分镜才会被采集:状态不为 error,有生图信息,有消息ID,没有生成图片,图片的有效期为24小时,是否继续?',
positiveText: '继续',
negativeText: '取消',
onPositiveClick: async () => {
da?.destroy()
let res = await window.book.GetImageUrlAndDownload(
reverseManageStore.selectBookTask.id,
value,
OperateBookType.BOOKTASK
OperateBookType.BOOKTASK,
false
)
if (res.code == 1) {
// 这边要修改下数据
for (let i = 0; i < res.data.length; i++) {
const element = res.data[i]
let findIndex = reverseManageStore.selectBookTaskDetail.findIndex(
(item) => item.id == element.id
)
if (findIndex != -1) {
reverseManageStore.selectBookTaskDetail[findIndex].outImagePath =
element.data.outImagePath
reverseManageStore.selectBookTaskDetail[findIndex].subImagePath =
element.data.subImagePath
reverseManageStore.selectBookTaskDetail[findIndex].mjMessage = element.data.mjMessage
}
}
message.success(res.message)
} else {
message.error(res.message)
}
}
})
}
// 进行一拆四操作
async function OneToFourBookTask() {
dialog.warning({
title: '一拆四提示',
content:
'是否一拆四(一拆四是个泛指,根据出的子图数量最少的),会自动生成多个批次任务并设置对应的图片!',
positiveText: '确定',
negativeText: '取消',
onPositiveClick: async () => {
let res = await window.book.OneToFourBookTask(reverseManageStore.selectBookTask.id)
if (res.code == 0) {
message.error(res.message)
return
}
for (let i = 0; i < res.data.length; i++) {
const element = res.data[i]
let index = reverseManageStore.selectBookTaskDetail.findIndex(
(item) => item.id == element.id
)
if (index != -1) {
reverseManageStore.selectBookTaskDetail[index].imageLock = element.imageLock
}
}
message.success(res.message)
}
})
}
// 进行一拆四操作
async function OneToFourBookTask() {
dialog.warning({
title: '一拆四提示',
content:
'是否一拆四(一拆四是个泛指,根据出的子图数量最少的),会自动生成多个批次任务并设置对应的图片!',
positiveText: '确定',
negativeText: '取消',
onPositiveClick: async () => {
let res = await window.book.OneToFourBookTask(reverseManageStore.selectBookTask.id)
if (res.code == 0) {
message.error(res.message)
return
}
message.success(res.message)
}
})
}
return {
reverseManageStore,
handleUpdateValue,
OneToFourBookTask,
softwareStore,
ImageLockOperation,
select,
blockOptions: [
{
label: '一键解锁',
key: 'unlock'
}
],
options
function renderOptionHandle({ node, option }) {
console.log('renderOptionHandle', node, option)
if (option.key == 'downloadMJImage') {
if (reverseManageStore.selectBookTask.imageCategory == BookImageCategory.MJ) {
return node
}
} else {
return node
}
})
}
let blockOptions = [
{
label: '一键锁定',
key: 'lock'
},
{
label: '一键解锁',
key: 'unlock'
},
{
label: 'MJ采集全部图片',
key: 'downloadMJImage'
},
{
label: '一拆四',
key: 'oneToFour'
}
]
</script>
@@ -84,7 +84,7 @@
:color="softwareStore.SoftColor.ORANGE"
style="margin-left: 5px"
size="small"
@click="GenerateImageAll"
@click="GenerateImageAll(true)"
>
一键生图
</n-button>
@@ -138,7 +138,13 @@ import VideoCanvas from '../../VideoSubtitle/VideoCanvas.vue'
import { SubtitleSavePositionType } from '../../../../../define/enum/waterMarkAndSubtitle.ts'
import { DEFINE_STRING } from '../../../../../define/define_string/index.ts'
import Setting from './Setting.vue'
import { BookType, OperateBookType } from '../../../../../define/enum/bookEnum.ts'
import {
BookBackTaskType,
BookImageCategory,
BookType,
OperateBookType,
TaskExecuteType
} from '../../../../../define/enum/bookEnum.ts'
import TranslateSetting from '../../Setting/TranslateSetting.vue'
import { TranslateType } from '../../../../../define/enum/translate.ts'
import { ContainsChineseOrPunctuation } from '../../../../../define/Tools/common.ts'
@@ -464,6 +470,10 @@ async function handleSelect(key) {
await Translate('translate_english')
break
case 'generate_space_image': //生成未生成的图片
await GenerateImageAll(false)
break
case 'translate_setting': // 翻译设置
await Translate('translate_setting')
break
@@ -780,18 +790,124 @@ async function TranslateService(from, to) {
}
/**
* 生成所有图片
* 根据指定类型为所有书籍任务生成图像
* @param {String} type - 小说图像类别
* @param {Boolean} cover - 是否覆盖现有图像
*/
async function GenerateImageAll() {
let res = await window.book.GenerateImageAll(
reverseManageStore.selectBookTask.id,
reverseManageStore.selectBookTask.imageCategory
)
if (res.code == 0) {
message.error(res.message)
async function AddFluxImageAll(type, cover) {
let messageName = DEFINE_STRING.BOOK.FLUX_API_IMAGE_GENERATE_RETURN
let taskType = BookBackTaskType.FLUX_API_IMAGE
if (type == BookImageCategory.FLUX_FORGE) {
messageName = DEFINE_STRING.BOOK.FLUX_FORGE_IMAGE_GENERATE_RETURN
taskType = BookBackTaskType.FLUX_FORGE_IMAGE
} else if (type == BookImageCategory.FLUX_API) {
messageName = DEFINE_STRING.BOOK.FLUX_API_IMAGE_GENERATE_RETURN
taskType = BookBackTaskType.FLUX_API_IMAGE
} else if (type == BookImageCategory.D3) {
messageName = DEFINE_STRING.BOOK.D3_IMAGE_GENERATE_RETURN
taskType = BookBackTaskType.D3_IMAGE
} else if (type == BookImageCategory.SD) {
messageName = DEFINE_STRING.BOOK.SD_IMAGE_GENERATE_RETURN
taskType = BookBackTaskType.SD_IMAGE
} else {
message.error('未知的图像类别')
return
}
message.success(res.message)
// 这边过滤所有的锁定的分镜
let bookTaskDetails = reverseManageStore.selectBookTaskDetail.filter((item) => !item.imageLock)
if (cover) {
// 添加全部的任务
let tasks = []
for (let i = 0; i < bookTaskDetails.length; i++) {
const element = bookTaskDetails[i]
tasks.push({
bookId: reverseManageStore.selectBook.id,
type: taskType,
executeType: TaskExecuteType.AUTO,
bookTaskId: reverseManageStore.selectBookTask.id,
bookTaskDetailId: element.id,
messageName: messageName
})
}
if (tasks.length <= 0) {
message.error('没有需要生成的分镜')
return
}
let res = await await window.task.AddMultiBookBackTask(tasks)
window.api.showGlobalMessage(res)
} else {
// 添加未生成的任务
let tasks = []
for (let i = 0; i < bookTaskDetails.length; i++) {
const element = bookTaskDetails[i]
if (!element.mjMessage) {
tasks.push({
bookId: reverseManageStore.selectBook.id,
type: taskType,
executeType: TaskExecuteType.AUTO,
bookTaskId: reverseManageStore.selectBookTask.id,
bookTaskDetailId: element.id,
messageName: messageName
})
}
}
if (tasks.length == 0) {
message.error('没有未生成的分镜,或者都被锁定了')
return
}
let res = await await window.task.AddMultiBookBackTask(tasks)
window.api.showGlobalMessage(res)
}
return
}
/**
* 生成所有图片
*/
async function GenerateImageAll(cover = true) {
let da = dialog.warning({
title: '生成所有图片提示',
content: `即将开始生成 ${cover ? '所有的' : '从未生成过的分镜'} 图片,当前的生图模式为 ${
reverseManageStore.selectBookTask.imageCategory
},开始执行会有1-20秒的延迟,除了被锁定的图片,其余的图片都会重新生成,是否继续?`,
positiveText: '继续',
negativeText: '取消',
onPositiveClick: async () => {
try {
da?.destroy()
debugger
if (reverseManageStore.selectBookTask.imageCategory == BookImageCategory.MJ) {
let res = await window.mj.AddMJGenerateImageTask(
reverseManageStore.selectBookTask.id,
OperateBookType.BOOKTASK,
DEFINE_STRING.BOOK.MJ_IMAGE_GENERATE_RETURN,
cover
)
if (res?.code == 1) {
message.success(res.message)
} else {
message.error(res.message)
}
} else if (reverseManageStore.selectBookTask.imageCategory == BookImageCategory.SD) {
await AddFluxImageAll(BookImageCategory.SD, cover)
} else if (
reverseManageStore.selectBookTask.imageCategory == BookImageCategory.FLUX_FORGE
) {
await AddFluxImageAll(BookImageCategory.FLUX_FORGE, cover)
} else if (reverseManageStore.selectBookTask.imageCategory == BookImageCategory.FLUX_API) {
await AddFluxImageAll(BookImageCategory.FLUX_API, cover)
} else if (reverseManageStore.selectBookTask.imageCategory == BookImageCategory.D3) {
await AddFluxImageAll(BookImageCategory.D3, cover)
} else {
message.error('不支持的生图类型')
return
}
} catch (error) {
message.error(error.message)
}
}
})
}
/**
@@ -973,6 +1089,7 @@ let translateOptions = [
}
]
let generateOptions = [
{ label: '生成未出图分镜', key: 'generate_space_image' },
{
label: '停止生图',
key: 'stop_image_generate'
@@ -27,6 +27,7 @@ import DatatableAfterGpt from './DatatableAfterGpt.vue'
import DatatableGenerateImage from './DatatableGenerateImage.vue'
import ODataTableAction from '../Original/ODataTableAction.vue'
import SDReversePrompt from './SDReversePrompt.vue'
import BookTaskDetailOptions from '../Components/ManageBook/BookTaskDetailOptions.vue'
let softwareStore = useSoftwareStore()
let reverseManageStore = useReverseManageStore()
@@ -117,7 +118,9 @@ const columns = [
},
{
//
title: '参数',
title(row) {
return h(BookTaskDetailOptions, { style: 'font-size: 24px;margin-left: 5px' })
},
key: 'parameter',
width: '110',
render(row, index) {
@@ -126,7 +129,7 @@ const columns = [
},
{
title() {
return h(DatatableHeaderImage)
return h(DatatableHeaderImage, { style: 'font-size: 24px; margin-left: 5px' })
},
width: 300,
className: 'empty-margin',
@@ -1,6 +1,14 @@
<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 size="small" strong secondary type="default">{{
reverseManageStore.selectBook.name
}}</n-button>
<n-button
style="margin-left: 5px"
:render-icon="renderIcon"
size="small"
type="info"
@click="AddBookDialog()"
>新增</n-button
>
<n-button style="margin-left: 5px" size="small" type="info" @click="GenerateAllTaskImage()"
@@ -54,14 +62,15 @@ import {
NDataTable,
NIcon,
NDropdown,
NPerformantEllipsis
NPerformantEllipsis,
NTag
} from 'naive-ui'
import { useReverseManageStore } from '../../../../stores/reverseManage'
import { useSoftwareStore } from '../../../../stores/software'
import { AddSharp, Open } from '@vicons/ionicons5'
import BookTaskListAction from './Components/ManageBook/BookTaskListAction.vue'
import { useRouter } from 'vue-router'
import { OperateBookType } from '../../../../define/enum/bookEnum'
import { GetBookTaskDetailStatusLabel, 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'
@@ -137,7 +146,10 @@ function createColumns() {
{
title: '状态',
key: 'status',
width: 100
width: 100,
render(row) {
return renderStatus(row)
}
},
{
title: '失败原因',
@@ -185,6 +197,14 @@ function createOptions(row) {
]
}
function renderStatus(row) {
return h(
NTag,
{ bordered: false, type: GetBookTaskDetailStatusLabel(row.status).type },
{ default: GetBookTaskDetailStatusLabel(row.status).label }
)
}
async function HDImage(value) {
softwareStore.spin.spinning = true
softwareStore.spin.tip = '正在进行高清检查。。。'
@@ -397,7 +417,7 @@ async function GenerateAllTaskImage() {
[...checkedRowKeysRef.value],
OperateBookType.ASSIGNBOOKTASK
)
window.api.showGlobalMessageDialog(res);
window.api.showGlobalMessageDialog(res)
softwareStore.spin.spinning = false
}
})
@@ -35,7 +35,6 @@
</n-popover>
<n-input
:status="input_status"
size="tiny"
placeholder="请生成出图命令或是提示词"
type="textarea"
@@ -178,7 +177,6 @@ async function SingleGenerateImage() {
//
async function NextGenerateImage() {
let res = undefined
let bookTaskDetails = reverseManageStore.selectBookTaskDetail.filter(
(item, index) => index >= props.index && !item.imageLock
@@ -382,6 +382,9 @@ async function AddFluxImageAll(type, cover) {
if (type == BookImageCategory.FLUX_FORGE) {
messageName = DEFINE_STRING.BOOK.FLUX_FORGE_IMAGE_GENERATE_RETURN
taskType = BookBackTaskType.FLUX_FORGE_IMAGE
} else if (type == BookImageCategory.FLUX_API) {
messageName = DEFINE_STRING.BOOK.FLUX_API_IMAGE_GENERATE_RETURN
taskType = BookBackTaskType.FLUX_API_IMAGE
} else if (type == BookImageCategory.D3) {
messageName = DEFINE_STRING.BOOK.D3_IMAGE_GENERATE_RETURN
taskType = BookBackTaskType.D3_IMAGE
@@ -465,7 +468,7 @@ async function GenerateImageAll(cover = true) {
} else if (reverseManageStore.selectBookTask.imageCategory == BookImageCategory.FLUX_FORGE) {
await AddFluxImageAll(BookImageCategory.FLUX_FORGE, cover)
} else if (reverseManageStore.selectBookTask.imageCategory == BookImageCategory.FLUX_API) {
await AddFluxImageAll(BookImageCategory.FLUX_FORGE, cover)
await AddFluxImageAll(BookImageCategory.FLUX_API, cover)
} else if (reverseManageStore.selectBookTask.imageCategory == BookImageCategory.D3) {
await AddFluxImageAll(BookImageCategory.D3, cover)
} else {
@@ -6,13 +6,11 @@
classMame="cd-22223"
:max-height="maxHeight"
:loading="softwareStore.loading.originDatatableDataLoading"
:row-key="rowKey"
:columns="createColumns({})"
:data="reverseManageStore.selectBookTaskDetail"
:pagination="false"
:bordered="false"
:scroll-x="0"
@update:checked-row-keys="handleCheck"
/>
</div>
</template>
@@ -30,7 +28,9 @@ import ODataTableHeaderPrompt from './ODatatableHeaderPrompt.vue'
import ODatatablePrompt from './ODatatablePrompt.vue'
import ODataTableAction from './ODataTableAction.vue'
import DatatableHeaderGenerateImage from '../MJReverse/DatatableHeaderGenerateImage.vue'
import DatatableHeaderImage from '../MJReverse/DatatableHeaderImage.vue'
import DatatableGenerateImage from '../MJReverse/DatatableGenerateImage.vue'
import BookTaskDetailOptions from '../Components/ManageBook/BookTaskDetailOptions.vue'
import { useReverseManageStore } from '../../../../../stores/reverseManage'
import { useSoftwareStore } from '../../../../../stores/software'
let reverseManageStore = useReverseManageStore()
@@ -141,7 +141,9 @@ const createColumns = ({}) => {
},
{
//
title: '参数',
title(row) {
return h(BookTaskDetailOptions, { style: 'font-size: 24px;margin-left: 5px' })
},
key: 'parameter',
width: '130',
render(row, index) {
@@ -151,7 +153,8 @@ const createColumns = ({}) => {
{
//
title(row) {
return h(DatatableHeaderGenerateImage)
// return h(DatatableHeaderGenerateImage)
return h(DatatableHeaderImage, { style: 'font-size: 24px; margin-left: 5px' })
},
key: 'options',
className: 'empty-margin',
@@ -0,0 +1,12 @@
<template>
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 24 24"
>
<path
d="M16.59 9H15V4c0-.55-.45-1-1-1h-4c-.55 0-1 .45-1 1v5H7.41c-.89 0-1.34 1.08-.71 1.71l4.59 4.59c.39.39 1.02.39 1.41 0l4.59-4.59c.63-.63.19-1.71-.7-1.71zM5 19c0 .55.45 1 1 1h12c.55 0 1-.45 1-1s-.45-1-1-1H6c-.55 0-1 .45-1 1z"
fill="currentColor"
></path>
</svg>
</template>
@@ -0,0 +1,12 @@
<template>
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 24 24"
>
<path
d="M4 18h11c.55 0 1-.45 1-1s-.45-1-1-1H4c-.55 0-1 .45-1 1s.45 1 1 1zm0-5h8c.55 0 1-.45 1-1s-.45-1-1-1H4c-.55 0-1 .45-1 1s.45 1 1 1zM3 7c0 .55.45 1 1 1h11c.55 0 1-.45 1-1s-.45-1-1-1H4c-.55 0-1 .45-1 1zm17.3 7.88L17.42 12l2.88-2.88a.996.996 0 1 0-1.41-1.41L15.3 11.3a.996.996 0 0 0 0 1.41l3.59 3.59c.39.39 1.02.39 1.41 0c.38-.39.39-1.03 0-1.42z"
fill="currentColor"
></path>
</svg>
</template>
@@ -0,0 +1,12 @@
<template>
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 24 24"
>
<path
d="M19 4H5a2 2 0 0 0-2 2v12c0 1.1.9 2 2 2h3c.55 0 1-.45 1-1s-.45-1-1-1H5V8h14v10h-3c-.55 0-1 .45-1 1s.45 1 1 1h3c1.1 0 2-.9 2-2V6a2 2 0 0 0-2-2zm-7.35 6.35l-2.79 2.79c-.32.32-.1.86.35.86H11v5c0 .55.45 1 1 1s1-.45 1-1v-5h1.79c.45 0 .67-.54.35-.85l-2.79-2.79c-.19-.2-.51-.2-.7-.01z"
fill="currentColor"
></path>
</svg>
</template>
@@ -0,0 +1,14 @@
<template>
<div>
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 24 24"
>
<path
d="M10 16h4c.55 0 1-.45 1-1v-5h1.59c.89 0 1.34-1.08.71-1.71L12.71 3.7a.996.996 0 0 0-1.41 0L6.71 8.29c-.63.63-.19 1.71.7 1.71H9v5c0 .55.45 1 1 1zm-4 2h12c.55 0 1 .45 1 1s-.45 1-1 1H6c-.55 0-1-.45-1-1s.45-1 1-1z"
fill="currentColor"
></path>
</svg>
</div>
</template>