feat(release): migrate GeekAI v4.3.0 to open source

- Sync backend and frontend from GeekAI Plus v4.3.0

- Remove commercial License flows and update open-source deployment defaults

- Preserve Docker Compose deployment and bump image tags to v4.3.0

BREAKING CHANGE: commercial License configuration and related endpoints are removed
This commit is contained in:
RockYang
2026-08-11 14:51:20 +08:00
parent 37e024acea
commit 9ccff4efbc
219 changed files with 29212 additions and 10802 deletions
+41
View File
@@ -7,6 +7,8 @@
import { getAdminToken, getUserToken, removeAdminToken, removeUserToken } from '@/store/session'
import axios from 'axios'
import { showMessageError } from '@/utils/dialog'
import { replaceImg } from '@/utils/libs'
// Blob 数据读取和解析的辅助函数
export async function parseBlobResponse(blob) {
@@ -107,6 +109,19 @@ export function httpPost(url, data = {}, options = {}) {
})
}
export function httpPatch(url, data = {}, options = {}) {
return new Promise((resolve, reject) => {
axios
.patch(url, data, options)
.then((response) => {
resolve(response.data)
})
.catch((err) => {
reject(err)
})
})
}
export function httpDownload(url) {
return new Promise((resolve, reject) => {
axios({
@@ -139,3 +154,29 @@ export function httpPostDownload(url, data) {
})
})
}
// 文件下载
export const downloadFile = async (item, key) => {
const url = replaceImg(item[key])
const downloadURL = `/api/download?url=${url}`
const urlObj = new URL(url)
const fileName = urlObj.pathname.split('/').pop()
item.downloading = true
try {
const response = await httpDownload(downloadURL)
const blob = new Blob([response.data])
const link = document.createElement('a')
link.href = URL.createObjectURL(blob)
link.download = fileName
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
URL.revokeObjectURL(link.href)
item.downloading = false
} catch (error) {
showMessageError('下载失败')
item.downloading = false
}
}
+74
View File
@@ -9,6 +9,7 @@
* Util lib functions
*/
import { showConfirmDialog } from 'vant'
import { httpGet } from '@/utils/http'
// generate a random string
export function randString(length) {
@@ -260,3 +261,76 @@ export function isChrome() {
export function formatDateTime(timestamp, format = 'yyyy-MM-dd HH:mm:ss') {
return dateFormat(timestamp, format)
}
export function isWechat() {
const ua = navigator.userAgent.toLowerCase()
return ua.indexOf('micromessenger') !== -1
}
// 默认缩略图模板(本地存储格式)
const DEFAULT_THUMB_TEMPLATE = '?imageView2/4/w/{width}/h/{height}/q/75'
const THUMB_TEMPLATE_KEY = 'GEEKAI_THUMB_TEMPLATE'
/**
* 初始化缩略图模板(从后端加载并缓存到localStorage
* @returns {Promise<void>}
*/
export async function initThumbTemplate() {
try {
const res = await httpGet('/api/config/oss/thumb')
if (res.data && res.data.template) {
const template = res.data.template || DEFAULT_THUMB_TEMPLATE
localStorage.setItem(THUMB_TEMPLATE_KEY, template)
return
}
} catch (error) {
console.warn('获取缩略图模板失败,使用默认模板:', error)
}
// 获取失败时使用默认模板并缓存
localStorage.setItem(THUMB_TEMPLATE_KEY, DEFAULT_THUMB_TEMPLATE)
}
/**
* 获取缓存的缩略图模板
* @returns {string} 缩略图模板
*/
function getCachedThumbTemplate() {
const cached = localStorage.getItem(THUMB_TEMPLATE_KEY)
return cached || DEFAULT_THUMB_TEMPLATE
}
/**
* 生成缩略图URL
* @param {string} originalURL - 原始图片URL
* @param {number} width - 缩略图宽度
* @param {number} height - 缩略图高度,0表示自适应
* @param {string} template - 缩略图模板(可选),如果不提供则从localStorage获取
* @returns {string} 缩略图URL
*/
export function getThumbURL(originalURL, width = 300, height = 0, template = null) {
if (!originalURL) {
return originalURL
}
// 如果没有提供模板,从localStorage获取
if (!template) {
template = getCachedThumbTemplate()
}
// 如果模板为空字符串,返回原图(表示不支持缩略图)
if (template === '') {
return originalURL
}
// 如果模板为空,使用默认模板(降级方案)
if (!template) {
template = DEFAULT_THUMB_TEMPLATE
}
// 替换变量
const thumbURL = template.replace(/{width}/g, width).replace(/{height}/g, height)
// 拼接原始URL和缩略图参数
return originalURL + thumbURL
}