feat(web): 品牌检测/图片生成服务端化——URL 统一 https+域名,入口文件带 hash 防长缓存失效
- brand/image 本地执行 API 服务端化(主机A shufu-web-api:15126,nginx 转发 /api/brand/* 等) - 前端撤销本地回连逻辑(local-http 删除,http.ts/brand.ts 还原为域名相对路径) - 版本更新改桌面桥 do_update_app(原 Flask /api/update/do 桥化,Web 无更新入口) - 品牌检测页 Web 可用(hasBridge 恢复 blanket 判定:文件选择走浏览器降级、任务/SSE 走域名) - vite 入口文件带内容 hash(/assets 配了 immutable 长缓存,无 hash 入口导致更新永不生效) - public/logo.jpg:Web 版 /logo.jpg 素材(原 app_client/logo.jpg 随桌面瘦身移除)
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
@@ -148,8 +148,9 @@ const runMode = ref<'immediate' | 'queue'>('immediate')
|
||||
const submitting = ref(false)
|
||||
const tasks = ref<BrandTaskItem[]>([])
|
||||
|
||||
// 品牌检测由桌面客户端本地执行:以"文件夹选择"桥(Web 降级桥不提供)判定桌面运行时,浏览器下仅可预览
|
||||
const hasBridge = computed(() => Boolean(getPywebviewApi()?.select_brand_folder))
|
||||
// 品牌检测已服务端化(/api/brand/* 走域名):浏览器降级桥提供文件选择,Web 端可用;
|
||||
// 文件夹选择/模板桥等降级桥未实现的方法在点击时提示"仅桌面端"
|
||||
const hasBridge = computed(() => Boolean(getPywebviewApi()))
|
||||
const hasUid = computed(() => {
|
||||
const raw = typeof window === 'undefined' ? '' : window.localStorage.getItem('uid') || ''
|
||||
const numeric = Number(raw.trim())
|
||||
|
||||
@@ -76,10 +76,10 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
import { computed, onMounted, ref, watch } from 'vue'
|
||||
import { requestGetJson } from '@/shared/api/http'
|
||||
import { buildJavaUrl } from '@/shared/api/url'
|
||||
import { isDesktopRuntime } from '@/shared/bridges/pywebview'
|
||||
import { getPywebviewApi, isDesktopRuntime } from '@/shared/bridges/pywebview'
|
||||
import { resolvePageHref } from '@/shared/page-prefix'
|
||||
|
||||
const username = ref('')
|
||||
@@ -90,10 +90,8 @@ const updateReady = ref(false)
|
||||
const updateFileUrl = ref('')
|
||||
const toastText = ref('')
|
||||
|
||||
// 桌面端走 Flask /logout(清 cookie 302 登录页);Web 独立部署 / dev 跳登录页并清本地 token(login.html?logout=1)
|
||||
const logoutHref = computed(() =>
|
||||
isDesktopRuntime.value ? '/logout' : `${resolvePageHref('/new_web_source/login.html')}?logout=1`,
|
||||
)
|
||||
// 桌面端原 Flask /logout 已随瘦身下线:统一跳登录页并清本地 token(login.html?logout=1)
|
||||
const logoutHref = computed(() => `${resolvePageHref('/new_web_source/login.html')}?logout=1`)
|
||||
|
||||
type PermissionState = { amazon: boolean; video: boolean; image: boolean }
|
||||
const permissionState = ref<PermissionState>({ amazon: false, video: false, image: false })
|
||||
@@ -252,14 +250,12 @@ async function doUpdate() {
|
||||
updateHint.value = '正在下载并准备更新,程序将自动退出...'
|
||||
updateReady.value = false
|
||||
try {
|
||||
const resp = await window.fetch('/api/update/do', {
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ file_url: updateFileUrl.value }),
|
||||
})
|
||||
const result = await resp.json().catch(() => ({}))
|
||||
updateHint.value = result.success ? '更新已启动,程序即将退出...' : (result.error || '更新启动失败')
|
||||
// 版本更新是桌面客户端专属动作:经浏览器桥调用本地 update 下载/启动(服务端化后无 /api/update/do)
|
||||
const bridge = getPywebviewApi()
|
||||
const result = bridge?.do_update_app ? await bridge.do_update_app(updateFileUrl.value) : undefined
|
||||
updateHint.value = result?.success
|
||||
? '更新已启动,程序即将退出...'
|
||||
: (result?.error || '当前环境不支持自动更新')
|
||||
} catch {
|
||||
updateHint.value = '请求更新失败,请重试'
|
||||
}
|
||||
@@ -268,10 +264,16 @@ async function doUpdate() {
|
||||
onMounted(() => {
|
||||
void loadCurrentUser()
|
||||
void loadPermissions()
|
||||
// 版本检测/更新由桌面客户端 Flask 提供,Web 版不发起
|
||||
if (isDesktopRuntime.value) {
|
||||
void fetchVersion().catch(() => undefined)
|
||||
}
|
||||
// 版本检测/更新仅桌面客户端(本地 Flask image 蓝图)提供;桌面桥注入后立即拉取
|
||||
watch(
|
||||
isDesktopRuntime,
|
||||
(runtime) => {
|
||||
if (runtime) {
|
||||
void fetchVersion().catch(() => undefined)
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
)
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -60,6 +60,17 @@ function createHttpClient(): AxiosInstance {
|
||||
})
|
||||
|
||||
instance.interceptors.request.use((config: InternalAxiosRequestConfig) => {
|
||||
// 携带本地登录令牌:桌面端同源 cookie 仍可用;dev(5173) 无 cookie 时靠 Bearer 过 Java 鉴权
|
||||
try {
|
||||
if (config.url && config.url.indexOf('/newApi') === 0 && typeof window !== 'undefined') {
|
||||
const token = window.localStorage.getItem('aiimage_auth_token') || ''
|
||||
if (token) {
|
||||
config.headers.Authorization = `Bearer ${token}`
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
/* 忽略读取令牌异常 */
|
||||
}
|
||||
return config
|
||||
})
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { ref } from 'vue';
|
||||
|
||||
import { webFallbackApi } from './web-fallback';
|
||||
import { isDesktopRuntime } from '@/shared/runtime-env';
|
||||
|
||||
export interface UploadedJavaFile {
|
||||
fileKey: string;
|
||||
@@ -122,6 +121,8 @@ export interface PywebviewApi {
|
||||
not_found?: boolean;
|
||||
error?: string;
|
||||
}>;
|
||||
/** 版本更新(桌面专属):下载更新包并启动 update.exe 后退出主程序(原 Flask /api/update/do 桥化) */
|
||||
do_update_app?: (fileUrl: string) => Promise<{ success: boolean; error?: string }>;
|
||||
launch_yaoayanui?: () => Promise<{
|
||||
success: boolean;
|
||||
path?: string;
|
||||
@@ -197,8 +198,8 @@ declare global {
|
||||
let cachedPywebviewApi: PywebviewApi | undefined;
|
||||
let pywebviewReadyBound = false;
|
||||
|
||||
/** 当前是否运行在桌面客户端(pywebview)运行时;Web 独立部署下恒为 false */
|
||||
export const isDesktopRuntime = ref(false);
|
||||
/** 当前是否运行在桌面客户端(pywebview)运行时;Web 独立部署下恒为 false(见 runtime-env.ts 注释) */
|
||||
export { isDesktopRuntime };
|
||||
|
||||
function syncPywebviewApi() {
|
||||
cachedPywebviewApi = window.pywebview?.api;
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* 桌面运行时环境标志
|
||||
*
|
||||
* 独立模块避免共享模块之间循环依赖(pywebview.ts 写入、各页面读取)。
|
||||
* 桌面客户端窗口加载 Web 版 URL 后 pywebview 桥注入完成即置 true;
|
||||
* 初始为 false,页面在 pywebviewready 之后的交互/挂载阶段读取时已为 true。
|
||||
*
|
||||
* 注意:前端 URL 已全部统一走 https+域名(品牌检测/图片生成已服务端化),
|
||||
* 本地不再有任何 Flask API 回连,无需 LOCAL_API_BASE。
|
||||
*/
|
||||
import { ref } from 'vue'
|
||||
|
||||
/** 桌面客户端(pywebview 桥已注入)运行时标志;Web 独立部署下恒为 false */
|
||||
export const isDesktopRuntime = ref(false)
|
||||
@@ -71,13 +71,15 @@ export default defineConfig({
|
||||
'variant-collection': resolve(__dirname, 'variant-collection.html'),
|
||||
brand: resolve(__dirname, 'brand.html'),
|
||||
'image-video': resolve(__dirname, 'image-video.html'),
|
||||
image: resolve(__dirname, 'image.html'),
|
||||
'amazon-console': resolve(__dirname, 'amazon-console.html'),
|
||||
home: resolve(__dirname, 'home.html'),
|
||||
login: resolve(__dirname, 'login.html'),
|
||||
},
|
||||
output: {
|
||||
entryFileNames: (chunkInfo) =>
|
||||
chunkInfo.name === 'image-video' ? 'assets/[name]-[hash].js' : 'assets/[name].js',
|
||||
// 入口文件同样带内容 hash:/assets/ 静态服务配了 immutable 长缓存,
|
||||
// 无 hash 的入口文件会导致前端更新对用户永不生效(旧文件名被永久缓存)
|
||||
entryFileNames: 'assets/[name]-[hash].js',
|
||||
chunkFileNames: 'assets/[name]-[hash].js',
|
||||
assetFileNames: 'assets/[name]-[hash][extname]',
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user