🚧 adjust page route
This commit is contained in:
41
components.d.ts
vendored
41
components.d.ts
vendored
@@ -16,13 +16,13 @@ declare module 'vue' {
|
|||||||
ACard: typeof import('ant-design-vue/es')['Card']
|
ACard: typeof import('ant-design-vue/es')['Card']
|
||||||
ACascader: typeof import('ant-design-vue/es')['Cascader']
|
ACascader: typeof import('ant-design-vue/es')['Cascader']
|
||||||
AccountSetting: typeof import('./src/views/User/AccountSetting/AccountSetting.vue')['default']
|
AccountSetting: typeof import('./src/views/User/AccountSetting/AccountSetting.vue')['default']
|
||||||
AccountSettingBackup: typeof import('./src/views/User/AccountSetting/components/AccountSettingBackup/AccountSettingBackup.vue')['default']
|
AccountSettingBackup: typeof import('./src/views/User/AccountSetting/Pages/AccountSettingBackup/AccountSettingBackup.vue')['default']
|
||||||
AccountSettingHome: typeof import('./src/views/User/AccountSetting/components/AccountSettingHome/AccountSettingHome.vue')['default']
|
AccountSettingHome: typeof import('./src/views/User/AccountSetting/Pages/AccountSettingHome/AccountSettingHome.vue')['default']
|
||||||
AccountSettingInfo: typeof import('./src/views/User/AccountSetting/components/AccountSettingInfo/AccountSettingInfo.vue')['default']
|
AccountSettingInfo: typeof import('./src/views/User/AccountSetting/Pages/AccountSettingInfo/AccountSettingInfo.vue')['default']
|
||||||
AccountSettingLog: typeof import('./src/views/User/AccountSetting/components/AccountSettingLog/AccountSettingLog.vue')['default']
|
AccountSettingLog: typeof import('./src/views/User/AccountSetting/Pages/AccountSettingLog/AccountSettingLog.vue')['default']
|
||||||
AccountSettingSidebar: typeof import('./src/views/User/AccountSetting/components/AccountSettingSidebar/AccountSettingSidebar.vue')['default']
|
AccountSettingSidebar: typeof import('./src/views/User/AccountSetting/Pages/AccountSettingSidebar/AccountSettingSidebar.vue')['default']
|
||||||
AccountSettingStorage: typeof import('./src/views/User/AccountSetting/components/AccountSettingStorage/AccountSettingStorage.vue')['default']
|
AccountSettingStorage: typeof import('./src/views/User/AccountSetting/Pages/AccountSettingStorage/AccountSettingStorage.vue')['default']
|
||||||
AccountSettingTask: typeof import('./src/views/User/AccountSetting/components/AccountSettingTask/AccountSettingTask.vue')['default']
|
AccountSettingTask: typeof import('./src/views/User/AccountSetting/Pages/AccountSettingTask/AccountSettingTask.vue')['default']
|
||||||
ACheckbox: typeof import('ant-design-vue/es')['Checkbox']
|
ACheckbox: typeof import('ant-design-vue/es')['Checkbox']
|
||||||
ACheckboxGroup: typeof import('ant-design-vue/es')['CheckboxGroup']
|
ACheckboxGroup: typeof import('ant-design-vue/es')['CheckboxGroup']
|
||||||
ACol: typeof import('ant-design-vue/es')['Col']
|
ACol: typeof import('ant-design-vue/es')['Col']
|
||||||
@@ -68,6 +68,7 @@ declare module 'vue' {
|
|||||||
ASelect: typeof import('ant-design-vue/es')['Select']
|
ASelect: typeof import('ant-design-vue/es')['Select']
|
||||||
ASelectOption: typeof import('ant-design-vue/es')['SelectOption']
|
ASelectOption: typeof import('ant-design-vue/es')['SelectOption']
|
||||||
ASkeleton: typeof import('ant-design-vue/es')['Skeleton']
|
ASkeleton: typeof import('ant-design-vue/es')['Skeleton']
|
||||||
|
ASlider: typeof import('ant-design-vue/es')['Slider']
|
||||||
ASpace: typeof import('ant-design-vue/es')['Space']
|
ASpace: typeof import('ant-design-vue/es')['Space']
|
||||||
ASpin: typeof import('ant-design-vue/es')['Spin']
|
ASpin: typeof import('ant-design-vue/es')['Spin']
|
||||||
AStatistic: typeof import('ant-design-vue/es')['Statistic']
|
AStatistic: typeof import('ant-design-vue/es')['Statistic']
|
||||||
@@ -108,13 +109,13 @@ declare module 'vue' {
|
|||||||
CommonPhoneUpload: typeof import('./src/views/Phone/CommonPhoneUpload/CommonPhoneUpload.vue')['default']
|
CommonPhoneUpload: typeof import('./src/views/Phone/CommonPhoneUpload/CommonPhoneUpload.vue')['default']
|
||||||
CompareImage: typeof import('./src/views/Upscale/CompareImage.vue')['default']
|
CompareImage: typeof import('./src/views/Upscale/CompareImage.vue')['default']
|
||||||
Dashboard: typeof import('./src/views/Admin/System/Pages/Dashboard.vue')['default']
|
Dashboard: typeof import('./src/views/Admin/System/Pages/Dashboard.vue')['default']
|
||||||
DeleteConfirmModal: typeof import('./src/views/User/AccountSetting/components/AccountSettingTask/components/DeleteConfirmModal.vue')['default']
|
DeleteConfirmModal: typeof import('./src/views/User/AccountSetting/Pages/AccountSettingTask/components/DeleteConfirmModal.vue')['default']
|
||||||
DeleteOutlined: typeof import('@ant-design/icons-vue')['DeleteOutlined']
|
DeleteOutlined: typeof import('@ant-design/icons-vue')['DeleteOutlined']
|
||||||
DownloadOutlined: typeof import('@ant-design/icons-vue')['DownloadOutlined']
|
DownloadOutlined: typeof import('@ant-design/icons-vue')['DownloadOutlined']
|
||||||
DownOutlined: typeof import('@ant-design/icons-vue')['DownOutlined']
|
DownOutlined: typeof import('@ant-design/icons-vue')['DownOutlined']
|
||||||
DynamicTitle: typeof import('./src/components/DynamicTitle/DynamicTitle.vue')['default']
|
DynamicTitle: typeof import('./src/components/DynamicTitle/DynamicTitle.vue')['default']
|
||||||
EditOutlined: typeof import('@ant-design/icons-vue')['EditOutlined']
|
EditOutlined: typeof import('@ant-design/icons-vue')['EditOutlined']
|
||||||
EmailModal: typeof import('./src/views/User/AccountSetting/components/AccountSettingHome/EmailModal.vue')['default']
|
EmailModal: typeof import('./src/views/User/AccountSetting/Pages/AccountSettingHome/EmailModal.vue')['default']
|
||||||
ExclamationCircleOutlined: typeof import('@ant-design/icons-vue')['ExclamationCircleOutlined']
|
ExclamationCircleOutlined: typeof import('@ant-design/icons-vue')['ExclamationCircleOutlined']
|
||||||
EyeInvisibleOutlined: typeof import('@ant-design/icons-vue')['EyeInvisibleOutlined']
|
EyeInvisibleOutlined: typeof import('@ant-design/icons-vue')['EyeInvisibleOutlined']
|
||||||
EyeOutlined: typeof import('@ant-design/icons-vue')['EyeOutlined']
|
EyeOutlined: typeof import('@ant-design/icons-vue')['EyeOutlined']
|
||||||
@@ -127,6 +128,7 @@ declare module 'vue' {
|
|||||||
HeatmapPro: typeof import('./src/components/HeatmapPro/HeatmapPro.vue')['default']
|
HeatmapPro: typeof import('./src/components/HeatmapPro/HeatmapPro.vue')['default']
|
||||||
ImageBed: typeof import('./src/views/ImageBed/index.vue')['default']
|
ImageBed: typeof import('./src/views/ImageBed/index.vue')['default']
|
||||||
ImageEnhancer: typeof import('./src/components/ImageEnhancer/ImageEnhancer.vue')['default']
|
ImageEnhancer: typeof import('./src/components/ImageEnhancer/ImageEnhancer.vue')['default']
|
||||||
|
ImageEnhancerModal: typeof import('./src/components/ImageEnhancer/ImageEnhancerModal.vue')['default']
|
||||||
ImageShare: typeof import('./src/views/Share/ImageShare/ImageShare.vue')['default']
|
ImageShare: typeof import('./src/views/Share/ImageShare/ImageShare.vue')['default']
|
||||||
ImageToolbar: typeof import('./src/components/ImageToolbar/ImageToolbar.vue')['default']
|
ImageToolbar: typeof import('./src/components/ImageToolbar/ImageToolbar.vue')['default']
|
||||||
ImageUpload: typeof import('./src/components/ImageUpload/ImageUpload.vue')['default']
|
ImageUpload: typeof import('./src/components/ImageUpload/ImageUpload.vue')['default']
|
||||||
@@ -154,7 +156,7 @@ declare module 'vue' {
|
|||||||
PageError404: typeof import('./src/views/Admin/Error/PageError404.vue')['default']
|
PageError404: typeof import('./src/views/Admin/Error/PageError404.vue')['default']
|
||||||
PageError500: typeof import('./src/views/Admin/Error/PageError500.vue')['default']
|
PageError500: typeof import('./src/views/Admin/Error/PageError500.vue')['default']
|
||||||
ParameterSetting: typeof import('./src/views/Upscale/ParameterSetting.vue')['default']
|
ParameterSetting: typeof import('./src/views/Upscale/ParameterSetting.vue')['default']
|
||||||
PasswordModal: typeof import('./src/views/User/AccountSetting/components/AccountSettingHome/PasswordModal.vue')['default']
|
PasswordModal: typeof import('./src/views/User/AccountSetting/Pages/AccountSettingHome/PasswordModal.vue')['default']
|
||||||
PeopleAlbumDetail: typeof import('./src/views/Album/PeopleAlbum/PeopleAlbumDetail.vue')['default']
|
PeopleAlbumDetail: typeof import('./src/views/Album/PeopleAlbum/PeopleAlbumDetail.vue')['default']
|
||||||
PeopleAlbumIndex: typeof import('./src/views/Album/PeopleAlbum/PeopleAlbumIndex.vue')['default']
|
PeopleAlbumIndex: typeof import('./src/views/Album/PeopleAlbum/PeopleAlbumIndex.vue')['default']
|
||||||
PeopleAlbumList: typeof import('./src/views/Album/PeopleAlbum/PeopleAlbumList.vue')['default']
|
PeopleAlbumList: typeof import('./src/views/Album/PeopleAlbum/PeopleAlbumList.vue')['default']
|
||||||
@@ -164,7 +166,7 @@ declare module 'vue' {
|
|||||||
PhoalbumDetail: typeof import('./src/views/Album/Phoalbum/PhoalbumDetail.vue')['default']
|
PhoalbumDetail: typeof import('./src/views/Album/Phoalbum/PhoalbumDetail.vue')['default']
|
||||||
PhoalbumIndex: typeof import('./src/views/Album/Phoalbum/PhoalbumIndex.vue')['default']
|
PhoalbumIndex: typeof import('./src/views/Album/Phoalbum/PhoalbumIndex.vue')['default']
|
||||||
PhoalbumList: typeof import('./src/views/Album/Phoalbum/PhoalbumList.vue')['default']
|
PhoalbumList: typeof import('./src/views/Album/Phoalbum/PhoalbumList.vue')['default']
|
||||||
PhoneModal: typeof import('./src/views/User/AccountSetting/components/AccountSettingHome/PhoneModal.vue')['default']
|
PhoneModal: typeof import('./src/views/User/AccountSetting/Pages/AccountSettingHome/PhoneModal.vue')['default']
|
||||||
PhotoStack: typeof import('./src/components/PhotoStack/PhotoStack.vue')['default']
|
PhotoStack: typeof import('./src/components/PhotoStack/PhotoStack.vue')['default']
|
||||||
PlusOutlined: typeof import('@ant-design/icons-vue')['PlusOutlined']
|
PlusOutlined: typeof import('@ant-design/icons-vue')['PlusOutlined']
|
||||||
PlusSquareOutlined: typeof import('@ant-design/icons-vue')['PlusSquareOutlined']
|
PlusSquareOutlined: typeof import('@ant-design/icons-vue')['PlusSquareOutlined']
|
||||||
@@ -199,29 +201,30 @@ declare module 'vue' {
|
|||||||
ShareViewList: typeof import('./src/views/Share/ShareViewList/index.vue')['default']
|
ShareViewList: typeof import('./src/views/Share/ShareViewList/index.vue')['default']
|
||||||
Spin: typeof import('./src/components/MyUI/Spin/Spin.vue')['default']
|
Spin: typeof import('./src/components/MyUI/Spin/Spin.vue')['default']
|
||||||
StarButton: typeof import('./src/components/StarButton/StarButton.vue')['default']
|
StarButton: typeof import('./src/components/StarButton/StarButton.vue')['default']
|
||||||
StorageCard: typeof import('./src/views/User/AccountSetting/components/AccountSettingStorage/StorageCard.vue')['default']
|
StorageCard: typeof import('./src/views/User/AccountSetting/Pages/AccountSettingStorage/StorageCard.vue')['default']
|
||||||
StorageManagement: typeof import('./src/views/Admin/System/Pages/StorageManagement.vue')['default']
|
StorageManagement: typeof import('./src/views/Admin/System/Pages/StorageManagement.vue')['default']
|
||||||
SystemHeader: typeof import('./src/views/Admin/System/Components/SystemHeader.vue')['default']
|
SystemHeader: typeof import('./src/views/Admin/System/Components/SystemHeader.vue')['default']
|
||||||
SystemLogs: typeof import('./src/views/Admin/System/Pages/SystemLogs.vue')['default']
|
SystemLogs: typeof import('./src/views/Admin/System/Pages/SystemLogs.vue')['default']
|
||||||
SystemSidebar: typeof import('./src/views/Admin/System/Components/SystemSidebar.vue')['default']
|
SystemSidebar: typeof import('./src/views/Admin/System/Components/SystemSidebar.vue')['default']
|
||||||
TabletOutlined: typeof import('@ant-design/icons-vue')['TabletOutlined']
|
TabletOutlined: typeof import('@ant-design/icons-vue')['TabletOutlined']
|
||||||
TaskCard: typeof import('./src/views/User/AccountSetting/components/AccountSettingTask/components/TaskCard.vue')['default']
|
TaskCard: typeof import('./src/views/User/AccountSetting/Pages/AccountSettingTask/components/TaskCard.vue')['default']
|
||||||
TaskForm: typeof import('./src/views/User/AccountSetting/components/AccountSettingTask/components/TaskForm.vue')['default']
|
TaskForm: typeof import('./src/views/User/AccountSetting/Pages/AccountSettingTask/components/TaskForm.vue')['default']
|
||||||
TaskSchedule: typeof import('./src/components/TaskSchedule/TaskSchedule.vue')['default']
|
TaskSchedule: typeof import('./src/components/TaskSchedule/TaskSchedule.vue')['default']
|
||||||
TaskTypeSelector: typeof import('./src/views/User/AccountSetting/components/AccountSettingTask/components/TaskTypeSelector.vue')['default']
|
TaskTypeSelector: typeof import('./src/views/User/AccountSetting/Pages/AccountSettingTask/components/TaskTypeSelector.vue')['default']
|
||||||
|
TestPage: typeof import('./src/views/Test/TestPage.vue')['default']
|
||||||
ThingAlbumDetail: typeof import('./src/views/Album/ThingAlbum/ThingAlbumDetail.vue')['default']
|
ThingAlbumDetail: typeof import('./src/views/Album/ThingAlbum/ThingAlbumDetail.vue')['default']
|
||||||
ThingAlbumIndex: typeof import('./src/views/Album/ThingAlbum/ThingAlbumIndex.vue')['default']
|
ThingAlbumIndex: typeof import('./src/views/Album/ThingAlbum/ThingAlbumIndex.vue')['default']
|
||||||
ThingAlbumList: typeof import('./src/views/Album/ThingAlbum/ThingAlbumList.vue')['default']
|
ThingAlbumList: typeof import('./src/views/Album/ThingAlbum/ThingAlbumList.vue')['default']
|
||||||
ThirdPartyLoginModal: typeof import('./src/views/User/AccountSetting/components/AccountSettingHome/ThirdPartyLoginModal.vue')['default']
|
ThirdPartyLoginModal: typeof import('./src/views/User/AccountSetting/Pages/AccountSettingHome/ThirdPartyLoginModal.vue')['default']
|
||||||
Tooltip: typeof import('./src/components/MyUI/Tooltip/Tooltip.vue')['default']
|
Tooltip: typeof import('./src/components/MyUI/Tooltip/Tooltip.vue')['default']
|
||||||
UploadImage: typeof import('./src/views/Upscale/UploadImage.vue')['default']
|
UploadImage: typeof import('./src/views/Upscale/UploadImage.vue')['default']
|
||||||
UploadSetting: typeof import('./src/components/ImageUpload/UploadSetting.vue')['default']
|
UploadSetting: typeof import('./src/components/ImageUpload/UploadSetting.vue')['default']
|
||||||
Upscale: typeof import('./src/views/Upscale/index.vue')['default']
|
Upscale: typeof import('./src/views/Upscale/index.vue')['default']
|
||||||
UpscalePhoneUpload: typeof import('./src/views/Phone/UpscalePhoneUpload/UpscalePhoneUpload.vue')['default']
|
UpscalePhoneUpload: typeof import('./src/views/Phone/UpscalePhoneUpload/UpscalePhoneUpload.vue')['default']
|
||||||
UserAnalysis: typeof import('./src/views/Admin/System/Pages/UserAnalysis.vue')['default']
|
UserAnalysis: typeof import('./src/views/Admin/System/Pages/UserAnalysis.vue')['default']
|
||||||
UserCenterDynamic: typeof import('./src/views/User/PersonalCenter/components/UserCenterDynamic/UserCenterDynamic.vue')['default']
|
UserCenterDynamic: typeof import('./src/views/User/PersonalCenter/Pages/UserCenterDynamic/UserCenterDynamic.vue')['default']
|
||||||
UserCenterHome: typeof import('./src/views/User/PersonalCenter/components/UserCenterHome/UserCenterHome.vue')['default']
|
UserCenterHome: typeof import('./src/views/User/PersonalCenter/Pages/UserCenterHome/UserCenterHome.vue')['default']
|
||||||
UserCenterSetting: typeof import('./src/views/User/PersonalCenter/components/UserCenterSetting/UserCenterSetting.vue')['default']
|
UserCenterSetting: typeof import('./src/views/User/PersonalCenter/Pages/UserCenterSetting/UserCenterSetting.vue')['default']
|
||||||
UserInfoCard: typeof import('./src/components/CommentReply/src/UserInfoCard/UserInfoCard.vue')['default']
|
UserInfoCard: typeof import('./src/components/CommentReply/src/UserInfoCard/UserInfoCard.vue')['default']
|
||||||
UserList: typeof import('./src/views/Admin/System/Pages/UserList.vue')['default']
|
UserList: typeof import('./src/views/Admin/System/Pages/UserList.vue')['default']
|
||||||
UserOutlined: typeof import('@ant-design/icons-vue')['UserOutlined']
|
UserOutlined: typeof import('@ant-design/icons-vue')['UserOutlined']
|
||||||
|
@@ -34,7 +34,7 @@
|
|||||||
"@types/file-saver": "^2.0.7",
|
"@types/file-saver": "^2.0.7",
|
||||||
"@types/json-stringify-safe": "^5.0.3",
|
"@types/json-stringify-safe": "^5.0.3",
|
||||||
"@types/leaflet": "^1.9.17",
|
"@types/leaflet": "^1.9.17",
|
||||||
"@types/node": "^22.13.14",
|
"@types/node": "^22.13.17",
|
||||||
"@types/nprogress": "^0.2.3",
|
"@types/nprogress": "^0.2.3",
|
||||||
"@vladmandic/face-api": "^1.7.15",
|
"@vladmandic/face-api": "^1.7.15",
|
||||||
"@vuepic/vue-datepicker": "^11.0.2",
|
"@vuepic/vue-datepicker": "^11.0.2",
|
||||||
@@ -89,11 +89,11 @@
|
|||||||
"@vitejs/plugin-vue": "^5.2.3",
|
"@vitejs/plugin-vue": "^5.2.3",
|
||||||
"eslint-plugin-vue": "^10.0.0",
|
"eslint-plugin-vue": "^10.0.0",
|
||||||
"globals": "^16.0.0",
|
"globals": "^16.0.0",
|
||||||
"sass": "^1.86.0",
|
"sass": "^1.86.1",
|
||||||
"typescript": "^5.8.2",
|
"typescript": "^5.8.2",
|
||||||
"typescript-eslint": "^8.28.0",
|
"typescript-eslint": "^8.29.0",
|
||||||
"unplugin-vue-components": "^28.4.1",
|
"unplugin-vue-components": "^28.4.1",
|
||||||
"vite": "^6.2.3",
|
"vite": "^6.2.4",
|
||||||
"vite-plugin-bundle-obfuscator": "1.4.2",
|
"vite-plugin-bundle-obfuscator": "1.4.2",
|
||||||
"vite-plugin-chunk-split": "^0.5.0",
|
"vite-plugin-chunk-split": "^0.5.0",
|
||||||
"vue-tsc": "2.2.8"
|
"vue-tsc": "2.2.8"
|
||||||
|
852
src/components/ImageEnhancer/ImageEnhancerModal.vue
Normal file
852
src/components/ImageEnhancer/ImageEnhancerModal.vue
Normal file
@@ -0,0 +1,852 @@
|
|||||||
|
<template>
|
||||||
|
<div class="enhancer-modal-container">
|
||||||
|
<AFlex class="enhancer-modal-content" :vertical="false" align="center" justify="space-between">
|
||||||
|
<!-- 左侧控制面板 -->
|
||||||
|
<div class="enhancer-modal-left">
|
||||||
|
<ACard class="enhancer-modal-left-container" :bordered="false">
|
||||||
|
<!-- 上传区域 -->
|
||||||
|
<div class="enhancer-modal-upload">
|
||||||
|
<Spin :spinning="enhancer.uploading" indicator="magic-ring">
|
||||||
|
<AUploadDragger
|
||||||
|
name="image"
|
||||||
|
accept="image/*"
|
||||||
|
:multiple="false"
|
||||||
|
:directory="false"
|
||||||
|
:maxCount="1"
|
||||||
|
:beforeUpload="enhancer.beforeUpload"
|
||||||
|
:custom-request="enhancer.customUploadRequest"
|
||||||
|
:disabled="enhancer.uploading || enhancer.isProcessing"
|
||||||
|
:showUploadList="false">
|
||||||
|
<div class="enhancer-modal-upload-content">
|
||||||
|
<ABadge :offset="[-10, 10]">
|
||||||
|
<template #count>
|
||||||
|
<AAvatar :size="22" :src="successIcon" v-if="enhancer.imageData"/>
|
||||||
|
<AAvatar :size="22" :src="warnIcon" v-if="!enhancer.imageData"/>
|
||||||
|
</template>
|
||||||
|
<AAvatar shape="square" :size="60" :src="fileIcon"/>
|
||||||
|
</ABadge>
|
||||||
|
<span class="enhancer-modal-upload-text">
|
||||||
|
点击或拖拽上传图片
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</AUploadDragger>
|
||||||
|
</Spin>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 功能选择区 -->
|
||||||
|
<ADivider orientation="center" :plain="true">
|
||||||
|
<span class="enhancer-modal-divider-title">增强功能</span>
|
||||||
|
</ADivider>
|
||||||
|
|
||||||
|
<div class="enhancer-modal-function-selector">
|
||||||
|
<ARadioGroup v-model:value="enhancer.selectedFunction" button-style="solid" size="small"
|
||||||
|
style="width: 100%">
|
||||||
|
<ARadioButton value="upscale">图像升级</ARadioButton>
|
||||||
|
<ARadioButton value="deblur">去模糊</ARadioButton>
|
||||||
|
<ARadioButton value="denoise">去噪</ARadioButton>
|
||||||
|
<ARadioButton value="lowlight">弱光增强</ARadioButton>
|
||||||
|
</ARadioGroup>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 参数设置区 -->
|
||||||
|
<ADivider orientation="center" :plain="true">
|
||||||
|
<span class="enhancer-modal-divider-title">参数设置</span>
|
||||||
|
</ADivider>
|
||||||
|
|
||||||
|
<!-- 图像升级参数 -->
|
||||||
|
<div v-if="enhancer.selectedFunction === 'upscale'" class="enhancer-modal-params">
|
||||||
|
<div class="enhancer-modal-params-item">
|
||||||
|
<div class="enhancer-modal-params-item-content">
|
||||||
|
<span class="enhancer-modal-params-title">模型:</span>
|
||||||
|
<ASelect style="width: 100%" size="middle"
|
||||||
|
v-model:value="enhancer.upscaleParams.model"
|
||||||
|
:options="enhancer.upscaleModels">
|
||||||
|
</ASelect>
|
||||||
|
</div>
|
||||||
|
<div class="enhancer-modal-params-item-content">
|
||||||
|
<span class="enhancer-modal-params-title">比例:</span>
|
||||||
|
<ASelect style="width: 100%" size="middle"
|
||||||
|
v-model:value="enhancer.upscaleParams.scale"
|
||||||
|
:options="enhancer.upscaleScales">
|
||||||
|
</ASelect>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 去模糊参数 -->
|
||||||
|
<div v-if="enhancer.selectedFunction === 'deblur'" class="enhancer-modal-params">
|
||||||
|
<div class="enhancer-modal-params-item">
|
||||||
|
<div class="enhancer-modal-params-item-content">
|
||||||
|
<span class="enhancer-modal-params-title">强度:</span>
|
||||||
|
<ASlider v-model:value="enhancer.deblurParams.strength" :min="0" :max="100" :step="1"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 去噪参数 -->
|
||||||
|
<div v-if="enhancer.selectedFunction === 'denoise'" class="enhancer-modal-params">
|
||||||
|
<div class="enhancer-modal-params-item">
|
||||||
|
<div class="enhancer-modal-params-item-content">
|
||||||
|
<span class="enhancer-modal-params-title">强度:</span>
|
||||||
|
<ASlider v-model:value="enhancer.denoiseParams.strength" :min="0" :max="100" :step="1"/>
|
||||||
|
</div>
|
||||||
|
<div class="enhancer-modal-params-item-content">
|
||||||
|
<span class="enhancer-modal-params-title">保留细节:</span>
|
||||||
|
<ASlider v-model:value="enhancer.denoiseParams.preserveDetail" :min="0" :max="100" :step="1"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 弱光增强参数 -->
|
||||||
|
<div v-if="enhancer.selectedFunction === 'lowlight'" class="enhancer-modal-params">
|
||||||
|
<div class="enhancer-modal-params-item">
|
||||||
|
<div class="enhancer-modal-params-item-content">
|
||||||
|
<span class="enhancer-modal-params-title">亮度:</span>
|
||||||
|
<ASlider v-model:value="enhancer.lowlightParams.brightness" :min="0" :max="100" :step="1"/>
|
||||||
|
</div>
|
||||||
|
<div class="enhancer-modal-params-item-content">
|
||||||
|
<span class="enhancer-modal-params-title">对比度:</span>
|
||||||
|
<ASlider v-model:value="enhancer.lowlightParams.contrast" :min="0" :max="100" :step="1"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 处理按钮 -->
|
||||||
|
<ADivider></ADivider>
|
||||||
|
<AButton style="width: 100%;" size="middle" shape="default" type="primary" :loading="enhancer.isProcessing"
|
||||||
|
:disabled="!enhancer.imageData"
|
||||||
|
@click="startEnhance">
|
||||||
|
<template #icon>
|
||||||
|
<AAvatar shape="square" :size="20" :src="runIcon"/>
|
||||||
|
</template>
|
||||||
|
<span class="enhancer-modal-params-btn">开始处理</span>
|
||||||
|
</AButton>
|
||||||
|
</ACard>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 右侧图像预览区 -->
|
||||||
|
<div class="enhancer-modal-right">
|
||||||
|
<div
|
||||||
|
ref="canvasContainer"
|
||||||
|
class="canvas-container"
|
||||||
|
@mousedown="startDragging"
|
||||||
|
@mouseup="stopDragging"
|
||||||
|
@mouseleave="stopDragging"
|
||||||
|
@mousemove="dragImage"
|
||||||
|
@wheel="resizeImage"
|
||||||
|
@touchstart="touchStart"
|
||||||
|
@touchmove="touchMove"
|
||||||
|
@touchend="touchEnd"
|
||||||
|
>
|
||||||
|
<!-- 进度条 -->
|
||||||
|
<div class="canvas-progressbar">
|
||||||
|
<span class="canvas-progressbar-text">
|
||||||
|
{{ enhancer.msg }}
|
||||||
|
</span>
|
||||||
|
<AProgress
|
||||||
|
v-if="enhancer.isProcessing"
|
||||||
|
:stroke-color="{
|
||||||
|
'0%': '#108ee9',
|
||||||
|
'100%': '#87d068',}"
|
||||||
|
:percent="enhancer.progressBar"
|
||||||
|
:showInfo="false"
|
||||||
|
status="active"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 图片 -->
|
||||||
|
<canvas ref="canvas"></canvas>
|
||||||
|
|
||||||
|
<!-- 拖动条 -->
|
||||||
|
<div
|
||||||
|
class="dragLine"
|
||||||
|
v-if="enhancer.isDone"
|
||||||
|
ref="dragLine">
|
||||||
|
<div class="dragBall"
|
||||||
|
@mousedown.stop="startDraggingLine"
|
||||||
|
@mousemove.stop="dragLineFn"
|
||||||
|
@mouseup.stop="stopDraggingLine"
|
||||||
|
>
|
||||||
|
<svg width="24" viewBox="0 0 27 20">
|
||||||
|
<path fill="#ff3484" d="M9.6 0L0 9.6l9.6 9.6z"></path>
|
||||||
|
<path fill="#5fb3e5" d="M17 19.2l9.5-9.6L16.9 0z"></path>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 菜单 -->
|
||||||
|
<div class="floating-menu" @mousedown.stop v-if="enhancer.isDone && enhancer.processedImg">
|
||||||
|
<AFlex :vertical="false" align="center" justify="space-between" :gap="8">
|
||||||
|
<ATooltip placement="top" title="下载图片">
|
||||||
|
<AButton type="text" size="small" @click="downloadImage" class="menu-btn">
|
||||||
|
<template #icon>
|
||||||
|
<AAvatar :src="downloadIcon" class="menu-icon" :size="20"/>
|
||||||
|
</template>
|
||||||
|
</AButton>
|
||||||
|
</ATooltip>
|
||||||
|
<ATooltip placement="top" title="保存图片">
|
||||||
|
<AButton type="text" size="small" class="menu-btn" @click="saveImage">
|
||||||
|
<template #icon>
|
||||||
|
<AAvatar :src="saveIcon" :size="20" class="menu-icon"/>
|
||||||
|
</template>
|
||||||
|
</AButton>
|
||||||
|
</ATooltip>
|
||||||
|
<ATooltip placement="top" title="删除图片">
|
||||||
|
<AButton type="text" size="small" danger class="menu-btn" @click="deleteImage">
|
||||||
|
<template #icon>
|
||||||
|
<AAvatar :src="deleteIcon" :size="20" class="menu-icon"/>
|
||||||
|
</template>
|
||||||
|
</AButton>
|
||||||
|
</ATooltip>
|
||||||
|
</AFlex>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 图片信息 -->
|
||||||
|
<div class="image-info">
|
||||||
|
<ATag color="cyan" :bordered="false" v-if="enhancer.imageData">原图: {{ originalImageSize }}</ATag>
|
||||||
|
<ATag color="purple" :bordered="false" v-if="enhancer.processedImg">处理后: {{ processedImageSize }}</ATag>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</AFlex>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, reactive, computed, onMounted, onUnmounted, defineEmits } from 'vue';
|
||||||
|
import { message } from "ant-design-vue";
|
||||||
|
import Spin from "@/components/MyUI/Spin/Spin.vue";
|
||||||
|
import Upscaler from 'upscaler';
|
||||||
|
|
||||||
|
// 图标导入
|
||||||
|
import fileIcon from "@/assets/svgs/file.svg";
|
||||||
|
import successIcon from '@/assets/svgs/success.svg';
|
||||||
|
import warnIcon from '@/assets/svgs/warn.svg';
|
||||||
|
import runIcon from '@/assets/svgs/run.svg';
|
||||||
|
import downloadIcon from '@/assets/svgs/download.svg';
|
||||||
|
import saveIcon from '@/assets/svgs/save.svg';
|
||||||
|
import deleteIcon from '@/assets/svgs/deleted.svg';
|
||||||
|
|
||||||
|
// 定义事件
|
||||||
|
const emit = defineEmits(['save-image', 'close']);
|
||||||
|
|
||||||
|
// DOM引用
|
||||||
|
const canvasContainer = ref<HTMLDivElement | null>(null);
|
||||||
|
const canvas = ref<HTMLCanvasElement | null>(null);
|
||||||
|
const dragLine = ref<HTMLDivElement | null>(null);
|
||||||
|
|
||||||
|
// 图像处理实例
|
||||||
|
let upscaler: any = null;
|
||||||
|
|
||||||
|
// 状态管理
|
||||||
|
const enhancer = reactive({
|
||||||
|
// 基本状态
|
||||||
|
uploading: false,
|
||||||
|
isProcessing: false,
|
||||||
|
isDone: false,
|
||||||
|
msg: "",
|
||||||
|
progressBar: 0,
|
||||||
|
|
||||||
|
// 图像数据
|
||||||
|
imageData: "",
|
||||||
|
fileData: "",
|
||||||
|
processedImg: "",
|
||||||
|
input: null as any,
|
||||||
|
|
||||||
|
// 拖拽状态
|
||||||
|
dragging: false,
|
||||||
|
linePosition: 0,
|
||||||
|
draggingLine: false,
|
||||||
|
|
||||||
|
// 功能选择
|
||||||
|
selectedFunction: "upscale",
|
||||||
|
|
||||||
|
// 图像升级参数
|
||||||
|
upscaleParams: {
|
||||||
|
model: "x4",
|
||||||
|
scale: 4
|
||||||
|
},
|
||||||
|
upscaleModels: [
|
||||||
|
{label: "通用模型 x2", value: "x2"},
|
||||||
|
{label: "通用模型 x4", value: "x4"},
|
||||||
|
{label: "照片增强", value: "photo"},
|
||||||
|
{label: "动漫风格", value: "anime"}
|
||||||
|
],
|
||||||
|
upscaleScales: [
|
||||||
|
{label: "2x", value: 2},
|
||||||
|
{label: "4x", value: 4}
|
||||||
|
],
|
||||||
|
|
||||||
|
// 去模糊参数
|
||||||
|
deblurParams: {
|
||||||
|
strength: 50,
|
||||||
|
radius: 5
|
||||||
|
},
|
||||||
|
|
||||||
|
// 去噪参数
|
||||||
|
denoiseParams: {
|
||||||
|
strength: 50,
|
||||||
|
preserveDetail: 70
|
||||||
|
},
|
||||||
|
|
||||||
|
// 弱光增强参数
|
||||||
|
lowlightParams: {
|
||||||
|
brightness: 60,
|
||||||
|
contrast: 50
|
||||||
|
},
|
||||||
|
|
||||||
|
// 图片上传前的校验
|
||||||
|
async beforeUpload(file: File) {
|
||||||
|
enhancer.uploading = true;
|
||||||
|
const urlData = URL.createObjectURL(file);
|
||||||
|
const image = new Image();
|
||||||
|
image.src = urlData;
|
||||||
|
|
||||||
|
// 等待图片加载完成
|
||||||
|
await new Promise(resolve => {
|
||||||
|
image.onload = resolve;
|
||||||
|
});
|
||||||
|
|
||||||
|
await clear();
|
||||||
|
enhancer.fileData = urlData;
|
||||||
|
enhancer.uploading = false;
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
|
||||||
|
// 自定义上传图片请求
|
||||||
|
async customUploadRequest(_file: any) {
|
||||||
|
enhancer.imageData = enhancer.fileData;
|
||||||
|
await loadImage();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 图片尺寸信息
|
||||||
|
const originalImageSize = computed(() => {
|
||||||
|
if (!enhancer.imageData) return "";
|
||||||
|
const img = new Image();
|
||||||
|
img.src = enhancer.imageData;
|
||||||
|
return `${img.width}x${img.height}`;
|
||||||
|
});
|
||||||
|
|
||||||
|
const processedImageSize = computed(() => {
|
||||||
|
if (!enhancer.processedImg) return "";
|
||||||
|
const img = new Image();
|
||||||
|
img.src = enhancer.processedImg;
|
||||||
|
return `${img.width}x${img.height}`;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 清空数据
|
||||||
|
async function clear() {
|
||||||
|
enhancer.imageData = "";
|
||||||
|
enhancer.processedImg = "";
|
||||||
|
enhancer.isDone = false;
|
||||||
|
enhancer.msg = "";
|
||||||
|
enhancer.progressBar = 0;
|
||||||
|
enhancer.isProcessing = false;
|
||||||
|
enhancer.dragging = false;
|
||||||
|
enhancer.linePosition = 0;
|
||||||
|
enhancer.draggingLine = false;
|
||||||
|
enhancer.input = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加载图片
|
||||||
|
async function loadImage() {
|
||||||
|
if (!canvas.value || !enhancer.imageData) return;
|
||||||
|
|
||||||
|
const ctx = canvas.value.getContext('2d');
|
||||||
|
if (!ctx) return;
|
||||||
|
|
||||||
|
const img = new Image();
|
||||||
|
img.src = enhancer.imageData;
|
||||||
|
|
||||||
|
await new Promise(resolve => {
|
||||||
|
img.onload = resolve;
|
||||||
|
});
|
||||||
|
|
||||||
|
canvas.value.width = img.width;
|
||||||
|
canvas.value.height = img.height;
|
||||||
|
ctx.drawImage(img, 0, 0);
|
||||||
|
|
||||||
|
// 初始化拖动线位置
|
||||||
|
enhancer.linePosition = img.width / 2;
|
||||||
|
|
||||||
|
// 初始化Upscaler
|
||||||
|
if (!upscaler) {
|
||||||
|
upscaler = new Upscaler();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 开始图像增强处理
|
||||||
|
async function startEnhance() {
|
||||||
|
if (!enhancer.imageData || !canvas.value) {
|
||||||
|
message.warning("请先上传图片");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
enhancer.isProcessing = true;
|
||||||
|
enhancer.msg = "正在处理图片...";
|
||||||
|
const start = Date.now();
|
||||||
|
|
||||||
|
try {
|
||||||
|
const img = new Image();
|
||||||
|
img.src = enhancer.imageData;
|
||||||
|
|
||||||
|
await new Promise(resolve => {
|
||||||
|
img.onload = resolve;
|
||||||
|
});
|
||||||
|
|
||||||
|
let processedImage;
|
||||||
|
|
||||||
|
// 根据选择的功能进行不同的处理
|
||||||
|
switch (enhancer.selectedFunction) {
|
||||||
|
case 'upscale':
|
||||||
|
enhancer.msg = "正在进行图像升级...";
|
||||||
|
processedImage = await upscaler.upscale(img, {
|
||||||
|
model: enhancer.upscaleParams.model,
|
||||||
|
scale: enhancer.upscaleParams.scale,
|
||||||
|
progress: (progress: number) => {
|
||||||
|
enhancer.progressBar = Math.round(progress * 100);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'deblur':
|
||||||
|
enhancer.msg = "正在进行去模糊处理...";
|
||||||
|
// 使用upscaler的去模糊功能
|
||||||
|
processedImage = await simulateImageProcessing(img, 'deblur');
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'denoise':
|
||||||
|
enhancer.msg = "正在进行去噪处理...";
|
||||||
|
processedImage = await simulateImageProcessing(img, 'denoise');
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'lowlight':
|
||||||
|
enhancer.msg = "正在进行弱光增强...";
|
||||||
|
processedImage = await simulateImageProcessing(img, 'lowlight');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (processedImage) {
|
||||||
|
enhancer.processedImg = processedImage.src || processedImage;
|
||||||
|
enhancer.isDone = true;
|
||||||
|
enhancer.msg = `处理完成! 用时: ${((Date.now() - start) / 1000).toFixed(2)}秒`;
|
||||||
|
|
||||||
|
// 更新画布显示处理后的图片
|
||||||
|
updateCanvasWithProcessedImage();
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("图像处理失败", error);
|
||||||
|
message.error("图像处理失败,请重试");
|
||||||
|
enhancer.msg = "处理失败";
|
||||||
|
} finally {
|
||||||
|
enhancer.isProcessing = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 模拟图像处理(在实际实现中应替换为真实的处理逻辑)
|
||||||
|
async function simulateImageProcessing(img: HTMLImageElement, _type: string) {
|
||||||
|
// 模拟进度
|
||||||
|
let progress = 0;
|
||||||
|
const interval = setInterval(() => {
|
||||||
|
progress += Math.random() * 5;
|
||||||
|
enhancer.progressBar = Math.min(Math.round(progress), 99);
|
||||||
|
if (progress >= 100) {
|
||||||
|
clearInterval(interval);
|
||||||
|
}
|
||||||
|
}, 200);
|
||||||
|
|
||||||
|
// 这里应该是实际的图像处理逻辑
|
||||||
|
// 目前使用upscaler的基本功能模拟其他处理效果
|
||||||
|
try {
|
||||||
|
const result = await upscaler.upscale(img, {
|
||||||
|
model: 'x2',
|
||||||
|
scale: 1.5,
|
||||||
|
progress: (p: number) => {
|
||||||
|
enhancer.progressBar = Math.round(p * 100);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
clearInterval(interval);
|
||||||
|
return result;
|
||||||
|
} catch (error) {
|
||||||
|
clearInterval(interval);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新画布显示处理后的图片
|
||||||
|
function updateCanvasWithProcessedImage() {
|
||||||
|
if (!canvas.value || !enhancer.processedImg) return;
|
||||||
|
|
||||||
|
const ctx = canvas.value.getContext('2d');
|
||||||
|
if (!ctx) return;
|
||||||
|
|
||||||
|
const img = new Image();
|
||||||
|
img.src = enhancer.processedImg;
|
||||||
|
|
||||||
|
img.onload = () => {
|
||||||
|
canvas.value!.width = img.width;
|
||||||
|
canvas.value!.height = img.height;
|
||||||
|
ctx.drawImage(img, 0, 0);
|
||||||
|
|
||||||
|
// 重置拖动线位置
|
||||||
|
enhancer.linePosition = img.width / 2;
|
||||||
|
|
||||||
|
// 绘制对比效果
|
||||||
|
drawComparisonView();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 绘制对比视图
|
||||||
|
function drawComparisonView() {
|
||||||
|
if (!canvas.value || !enhancer.imageData || !enhancer.processedImg || !enhancer.isDone) return;
|
||||||
|
|
||||||
|
const ctx = canvas.value.getContext('2d');
|
||||||
|
if (!ctx) return;
|
||||||
|
|
||||||
|
const originalImg = new Image();
|
||||||
|
originalImg.src = enhancer.imageData;
|
||||||
|
|
||||||
|
const processedImg = new Image();
|
||||||
|
processedImg.src = enhancer.processedImg;
|
||||||
|
|
||||||
|
originalImg.onload = () => {
|
||||||
|
processedImg.onload = () => {
|
||||||
|
// 清除画布
|
||||||
|
ctx.clearRect(0, 0, canvas.value!.width, canvas.value!.height);
|
||||||
|
|
||||||
|
// 绘制处理后的图片
|
||||||
|
ctx.drawImage(processedImg, 0, 0, canvas.value!.width, canvas.value!.height);
|
||||||
|
|
||||||
|
// 绘制原图(左侧部分)
|
||||||
|
ctx.drawImage(
|
||||||
|
originalImg,
|
||||||
|
0, 0, originalImg.width, originalImg.height,
|
||||||
|
0, 0, enhancer.linePosition, canvas.value!.height
|
||||||
|
);
|
||||||
|
|
||||||
|
// 绘制分割线
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(enhancer.linePosition, 0);
|
||||||
|
ctx.lineTo(enhancer.linePosition, canvas.value!.height);
|
||||||
|
ctx.strokeStyle = '#ffffff';
|
||||||
|
ctx.lineWidth = 2;
|
||||||
|
ctx.stroke();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 拖动相关函数
|
||||||
|
function startDragging(_e: MouseEvent) {
|
||||||
|
enhancer.dragging = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function stopDragging() {
|
||||||
|
enhancer.dragging = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function dragImage(e: MouseEvent) {
|
||||||
|
if (!enhancer.dragging || !canvasContainer.value) return;
|
||||||
|
|
||||||
|
if (enhancer.isDone) {
|
||||||
|
// 更新拖动线位置
|
||||||
|
const rect = canvasContainer.value.getBoundingClientRect();
|
||||||
|
const x = e.clientX - rect.left;
|
||||||
|
enhancer.linePosition = Math.max(0, Math.min(canvas.value?.width || 0, x));
|
||||||
|
drawComparisonView();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function startDraggingLine(e: MouseEvent) {
|
||||||
|
e.preventDefault();
|
||||||
|
enhancer.draggingLine = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function stopDraggingLine() {
|
||||||
|
enhancer.draggingLine = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function dragLineFn(e: MouseEvent) {
|
||||||
|
if (!enhancer.draggingLine || !canvas.value || !canvasContainer.value) return;
|
||||||
|
|
||||||
|
const rect = canvasContainer.value.getBoundingClientRect();
|
||||||
|
const x = e.clientX - rect.left;
|
||||||
|
|
||||||
|
// 限制拖动范围在画布内
|
||||||
|
enhancer.linePosition = Math.max(0, Math.min(canvas.value.width, x));
|
||||||
|
|
||||||
|
// 重新绘制对比视图
|
||||||
|
drawComparisonView();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 缩放相关函数
|
||||||
|
function resizeImage(e: WheelEvent) {
|
||||||
|
e.preventDefault();
|
||||||
|
// 实现简单的缩放功能
|
||||||
|
if (!canvas.value || !enhancer.isDone) return;
|
||||||
|
|
||||||
|
// 这里可以实现缩放逻辑
|
||||||
|
}
|
||||||
|
|
||||||
|
// 触摸事件处理
|
||||||
|
function touchStart(e: TouchEvent) {
|
||||||
|
if (e.touches.length === 1) {
|
||||||
|
enhancer.dragging = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function touchMove(e: TouchEvent) {
|
||||||
|
if (!enhancer.dragging || !canvasContainer.value || e.touches.length !== 1) return;
|
||||||
|
|
||||||
|
const touch = e.touches[0];
|
||||||
|
const rect = canvasContainer.value.getBoundingClientRect();
|
||||||
|
const x = touch.clientX - rect.left;
|
||||||
|
|
||||||
|
if (enhancer.isDone) {
|
||||||
|
// 更新拖动线位置
|
||||||
|
enhancer.linePosition = Math.max(0, Math.min(canvas.value?.width || 0, x));
|
||||||
|
drawComparisonView();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function touchEnd() {
|
||||||
|
enhancer.dragging = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 下载图片
|
||||||
|
function downloadImage() {
|
||||||
|
if (!enhancer.processedImg) return;
|
||||||
|
|
||||||
|
const link = document.createElement('a');
|
||||||
|
link.href = enhancer.processedImg;
|
||||||
|
link.download = `enhanced_image_${Date.now()}.png`;
|
||||||
|
document.body.appendChild(link);
|
||||||
|
link.click();
|
||||||
|
document.body.removeChild(link);
|
||||||
|
|
||||||
|
message.success('图片下载成功');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存图片
|
||||||
|
function saveImage() {
|
||||||
|
if (!enhancer.processedImg) return;
|
||||||
|
emit('save-image', enhancer.processedImg);
|
||||||
|
message.success('图片已保存');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除图片
|
||||||
|
function deleteImage() {
|
||||||
|
clear();
|
||||||
|
message.success('图片已删除');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 组件挂载和卸载
|
||||||
|
onMounted(() => {
|
||||||
|
// 初始化Upscaler
|
||||||
|
upscaler = new Upscaler();
|
||||||
|
});
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
// 清理资源
|
||||||
|
if (enhancer.processedImg) {
|
||||||
|
URL.revokeObjectURL(enhancer.processedImg);
|
||||||
|
}
|
||||||
|
if (enhancer.imageData) {
|
||||||
|
URL.revokeObjectURL(enhancer.imageData);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.enhancer-modal-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
padding: 10px;
|
||||||
|
|
||||||
|
.enhancer-modal-content {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 15px;
|
||||||
|
|
||||||
|
.enhancer-modal-left {
|
||||||
|
width: 35%;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
.enhancer-modal-left-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
border-radius: 8px;
|
||||||
|
background-color: rgba(255, 255, 255, 0.8);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
|
||||||
|
padding: 15px;
|
||||||
|
|
||||||
|
.enhancer-modal-divider-title {
|
||||||
|
font-size: 13px;
|
||||||
|
color: rgba(80, 80, 90, 0.9);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.enhancer-modal-right {
|
||||||
|
width: 65%;
|
||||||
|
height: 100%;
|
||||||
|
border-radius: 8px;
|
||||||
|
overflow: hidden;
|
||||||
|
background-color: rgba(245, 245, 245, 0.5);
|
||||||
|
backdrop-filter: blur(5px);
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.enhancer-modal-upload {
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
|
||||||
|
.enhancer-modal-upload-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 20px 0;
|
||||||
|
gap: 10px;
|
||||||
|
|
||||||
|
.enhancer-modal-upload-text {
|
||||||
|
font-size: 14px;
|
||||||
|
color: rgba(80, 80, 90, 0.8);
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.enhancer-modal-function-selector {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.enhancer-modal-params {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
|
||||||
|
.enhancer-modal-params-item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
|
||||||
|
.enhancer-modal-params-item-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 5px;
|
||||||
|
|
||||||
|
.enhancer-modal-params-title {
|
||||||
|
font-size: 13px;
|
||||||
|
color: rgba(80, 80, 90, 0.9);
|
||||||
|
margin-bottom: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.enhancer-modal-params-btn {
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.canvas-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background-color: rgba(0, 0, 0, 0.02);
|
||||||
|
border-radius: 8px;
|
||||||
|
|
||||||
|
canvas {
|
||||||
|
max-width: 100%;
|
||||||
|
max-height: 100%;
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
|
||||||
|
.canvas-progressbar {
|
||||||
|
position: absolute;
|
||||||
|
top: 10px;
|
||||||
|
left: 10px;
|
||||||
|
right: 10px;
|
||||||
|
z-index: 10;
|
||||||
|
background-color: rgba(255, 255, 255, 0.7);
|
||||||
|
padding: 8px;
|
||||||
|
border-radius: 6px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||||
|
|
||||||
|
.canvas-progressbar-text {
|
||||||
|
font-size: 13px;
|
||||||
|
color: rgba(80, 80, 90, 0.9);
|
||||||
|
margin-bottom: 5px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dragLine {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
width: 2px;
|
||||||
|
background-color: #ffffff;
|
||||||
|
z-index: 5;
|
||||||
|
|
||||||
|
.dragBall {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
cursor: ew-resize;
|
||||||
|
background-color: rgba(255, 255, 255, 0.9);
|
||||||
|
border-radius: 50%;
|
||||||
|
padding: 2px;
|
||||||
|
box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.floating-menu {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 15px;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
background-color: rgba(255, 255, 255, 0.8);
|
||||||
|
backdrop-filter: blur(5px);
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 5px 10px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
||||||
|
z-index: 10;
|
||||||
|
|
||||||
|
.menu-btn {
|
||||||
|
margin: 0 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-icon {
|
||||||
|
opacity: 0.8;
|
||||||
|
transition: all 0.2s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-info {
|
||||||
|
position: absolute;
|
||||||
|
top: 10px;
|
||||||
|
right: 10px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 5px;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@@ -1,3 +0,0 @@
|
|||||||
import ImageEnhancer from './ImageEnhancer.vue';
|
|
||||||
|
|
||||||
export default ImageEnhancer;
|
|
11
src/router/modules/test.ts
Normal file
11
src/router/modules/test.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
export default [
|
||||||
|
{
|
||||||
|
path: '/test',
|
||||||
|
name: 'testPage',
|
||||||
|
component: () => import('@/views/Test/TestPage.vue'),
|
||||||
|
meta: {
|
||||||
|
requiresAuth: false,
|
||||||
|
title: 'testPage',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
];
|
@@ -1,13 +1,13 @@
|
|||||||
import UserCenterHome from "@/views/User/PersonalCenter/components/UserCenterHome/UserCenterHome.vue";
|
import UserCenterHome from "@/views/User/PersonalCenter/Pages/UserCenterHome/UserCenterHome.vue";
|
||||||
import UserCenterDynamic from "@/views/User/PersonalCenter/components/UserCenterDynamic/UserCenterDynamic.vue";
|
import UserCenterDynamic from "@/views/User/PersonalCenter/Pages/UserCenterDynamic/UserCenterDynamic.vue";
|
||||||
import UserCenterSetting from "@/views/User/PersonalCenter/components/UserCenterSetting/UserCenterSetting.vue";
|
import UserCenterSetting from "@/views/User/PersonalCenter/Pages/UserCenterSetting/UserCenterSetting.vue";
|
||||||
|
|
||||||
import AccountSettingHome from "@/views/User/AccountSetting/components/AccountSettingHome/AccountSettingHome.vue";
|
import AccountSettingHome from "@/views/User/AccountSetting/Pages/AccountSettingHome/AccountSettingHome.vue";
|
||||||
import AccountSettingInfo from "@/views/User/AccountSetting/components/AccountSettingInfo/AccountSettingInfo.vue";
|
import AccountSettingInfo from "@/views/User/AccountSetting/Pages/AccountSettingInfo/AccountSettingInfo.vue";
|
||||||
import AccountSettingStorage
|
import AccountSettingStorage
|
||||||
from "@/views/User/AccountSetting/components/AccountSettingStorage/AccountSettingStorage.vue";
|
from "@/views/User/AccountSetting/Pages/AccountSettingStorage/AccountSettingStorage.vue";
|
||||||
import AccountSettingBackup
|
import AccountSettingBackup
|
||||||
from "@/views/User/AccountSetting/components/AccountSettingBackup/AccountSettingBackup.vue";
|
from '@/views/User/AccountSetting/Pages/AccountSettingBackup/AccountSettingBackup.vue';
|
||||||
|
|
||||||
export default [
|
export default [
|
||||||
{
|
{
|
||||||
@@ -99,7 +99,7 @@ export default [
|
|||||||
{
|
{
|
||||||
path: '/main/user/setting/task',
|
path: '/main/user/setting/task',
|
||||||
name: 'AccountSettingTask',
|
name: 'AccountSettingTask',
|
||||||
component: () => import('@/views/User/AccountSetting/components/AccountSettingTask/AccountSettingTask.vue'),
|
component: () => import('@/views/User/AccountSetting/Pages/AccountSettingTask/AccountSettingTask.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
requiresAuth: true,
|
requiresAuth: true,
|
||||||
title: '定时任务'
|
title: '定时任务'
|
||||||
@@ -108,7 +108,7 @@ export default [
|
|||||||
{
|
{
|
||||||
path: '/main/user/setting/log',
|
path: '/main/user/setting/log',
|
||||||
name: 'AccountSettingLog',
|
name: 'AccountSettingLog',
|
||||||
component: () => import('@/views/User/AccountSetting/components/AccountSettingLog/AccountSettingLog.vue'),
|
component: () => import('@/views/User/AccountSetting/Pages/AccountSettingLog/AccountSettingLog.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
requiresAuth: true,
|
requiresAuth: true,
|
||||||
title: '执行记录'
|
title: '执行记录'
|
||||||
|
@@ -11,7 +11,7 @@ import phone_upload from "@/router/modules/phone_upload.ts";
|
|||||||
import user from "@/router/modules/user.ts";
|
import user from "@/router/modules/user.ts";
|
||||||
import system from "@/router/modules/system.ts";
|
import system from "@/router/modules/system.ts";
|
||||||
import preview from "@/router/modules/preview.ts";
|
import preview from "@/router/modules/preview.ts";
|
||||||
|
import test from "@/router/modules/test.ts";
|
||||||
const routes: Array<RouteRecordRaw> = [
|
const routes: Array<RouteRecordRaw> = [
|
||||||
...login,
|
...login,
|
||||||
...notFound,
|
...notFound,
|
||||||
@@ -21,6 +21,7 @@ const routes: Array<RouteRecordRaw> = [
|
|||||||
...user,
|
...user,
|
||||||
...system,
|
...system,
|
||||||
...preview,
|
...preview,
|
||||||
|
...test,
|
||||||
{
|
{
|
||||||
path: '/:pathMatch(.*)',
|
path: '/:pathMatch(.*)',
|
||||||
redirect: '/404',
|
redirect: '/404',
|
||||||
|
12
src/views/Test/TestPage.vue
Normal file
12
src/views/Test/TestPage.vue
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
|
||||||
|
import ImageEnhancerModal from "@/components/ImageEnhancer/ImageEnhancerModal.vue";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<ImageEnhancerModal/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
|
||||||
|
</style>
|
@@ -14,7 +14,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import Header from "@/layout/default/Header/Header.vue";
|
import Header from "@/layout/default/Header/Header.vue";
|
||||||
import AccountSettingSidebar
|
import AccountSettingSidebar
|
||||||
from "@/views/User/AccountSetting/components/AccountSettingSidebar/AccountSettingSidebar.vue";
|
from "@/views/User/AccountSetting/Pages/AccountSettingSidebar/AccountSettingSidebar.vue";
|
||||||
</script>
|
</script>
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.account-setting {
|
.account-setting {
|
||||||
|
@@ -79,7 +79,7 @@
|
|||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
|
||||||
import StorageCard from "@/views/User/AccountSetting/components/AccountSettingStorage/StorageCard.vue";
|
import StorageCard from "@/views/User/AccountSetting/Pages/AccountSettingStorage/StorageCard.vue";
|
||||||
import {addStorageConfigApi, listUserStorageConfigApi} from "@/api/storage";
|
import {addStorageConfigApi, listUserStorageConfigApi} from "@/api/storage";
|
||||||
import {message} from "ant-design-vue";
|
import {message} from "ant-design-vue";
|
||||||
|
|
Reference in New Issue
Block a user