mirror of
				https://github.com/whyour/qinglong.git
				synced 2025-10-31 08:56:06 +08:00 
			
		
		
		
	修改版本文件
This commit is contained in:
		
							parent
							
								
									3570cddce0
								
							
						
					
					
						commit
						0ab756665e
					
				|  | @ -7,7 +7,7 @@ import SystemService from '../services/system'; | |||
| import { celebrate, Joi } from 'celebrate'; | ||||
| import UserService from '../services/user'; | ||||
| import { EnvModel } from '../data/env'; | ||||
| import { promiseExec } from '../config/util'; | ||||
| import { parseVersion, promiseExec } from '../config/util'; | ||||
| import dayjs from 'dayjs'; | ||||
| 
 | ||||
| const route = Router(); | ||||
|  | @ -21,10 +21,9 @@ export default (app: Router) => { | |||
|       const userService = Container.get(UserService); | ||||
|       const authInfo = await userService.getUserInfo(); | ||||
|       const envCount = await EnvModel.count(); | ||||
|       const versionRegx = /.*export const version = \'(.*)\'\;/; | ||||
| 
 | ||||
|       const currentVersionFile = fs.readFileSync(config.versionFile, 'utf8'); | ||||
|       const version = currentVersionFile.match(versionRegx)![1]; | ||||
|       const { version, changeLog, changeLogLink } = await parseVersion( | ||||
|         config.versionFile, | ||||
|       ); | ||||
|       const lastCommitTime = ( | ||||
|         await promiseExec( | ||||
|           `cd ${config.rootPath} && git show -s --format=%ai | head -1`, | ||||
|  | @ -56,6 +55,8 @@ export default (app: Router) => { | |||
|           lastCommitTime: dayjs(lastCommitTime).unix(), | ||||
|           lastCommitId, | ||||
|           branch, | ||||
|           changeLog, | ||||
|           changeLogLink, | ||||
|         }, | ||||
|       }); | ||||
|     } catch (e) { | ||||
|  |  | |||
|  | @ -14,7 +14,7 @@ if (!process.env.QL_DIR) { | |||
|   process.env.QL_DIR = qlHomePath.replace(/\/$/g, ''); | ||||
| } | ||||
| 
 | ||||
| const lastVersionFile = `https://qn.whyour.cn/version.ts`; | ||||
| const lastVersionFile = `https://qn.whyour.cn/version.yaml`; | ||||
| 
 | ||||
| const rootPath = process.env.QL_DIR as string; | ||||
| const envFound = dotenv.config({ path: path.join(rootPath, '.env') }); | ||||
|  | @ -40,7 +40,7 @@ const sqliteFile = path.join(samplePath, 'database.sqlite'); | |||
| const authError = '错误的用户名密码,请重试'; | ||||
| const loginFaild = '请先登录!'; | ||||
| const configString = 'config sample crontab shareCode diy'; | ||||
| const versionFile = path.join(rootPath, 'src/version.ts'); | ||||
| const versionFile = path.join(rootPath, 'version.yaml'); | ||||
| 
 | ||||
| if (envFound.error) { | ||||
|   throw new Error("⚠️  Couldn't find .env file  ⚠️"); | ||||
|  |  | |||
|  | @ -6,6 +6,7 @@ import { exec } from 'child_process'; | |||
| import FormData from 'form-data'; | ||||
| import psTreeFun from 'pstree.remy'; | ||||
| import { promisify } from 'util'; | ||||
| import { load } from 'js-yaml'; | ||||
| 
 | ||||
| export function getFileContentByName(fileName: string) { | ||||
|   if (fs.existsSync(fileName)) { | ||||
|  | @ -482,3 +483,17 @@ export async function getPid(name: string) { | |||
|   let pid = (await execAsync(taskCommand)).stdout; | ||||
|   return Number(pid); | ||||
| } | ||||
| 
 | ||||
| interface IVersion { | ||||
|   version: string; | ||||
|   changeLogLink: string; | ||||
|   changeLog: string; | ||||
| } | ||||
| 
 | ||||
| export async function parseVersion(path: string): Promise<IVersion> { | ||||
|   return load(await promisify(fs.readFile)(path, 'utf8')) as IVersion; | ||||
| } | ||||
| 
 | ||||
| export async function parseContentVersion(content: string): Promise<IVersion> { | ||||
|   return load(content) as IVersion; | ||||
| } | ||||
|  |  | |||
|  | @ -4,13 +4,11 @@ import * as Tracing from '@sentry/tracing'; | |||
| import Logger from './logger'; | ||||
| import config from '../config'; | ||||
| import fs from 'fs'; | ||||
| import { parseVersion } from '../config/util'; | ||||
| 
 | ||||
| export default ({ expressApp }: { expressApp: Application }) => { | ||||
|   const versionRegx = /.*export const version = \'(.*)\'\;/; | ||||
| export default async ({ expressApp }: { expressApp: Application }) => { | ||||
|   const { version } = await parseVersion(config.versionFile); | ||||
| 
 | ||||
|   const currentVersionFile = fs.readFileSync(config.versionFile, 'utf8'); | ||||
|   const currentVersion = currentVersionFile.match(versionRegx)![1]; | ||||
|    | ||||
|   Sentry.init({ | ||||
|     dsn: 'https://f4b5b55fb3c645b29a5dc2d70a1a4ef4@o1098464.ingest.sentry.io/6122819', | ||||
|     integrations: [ | ||||
|  | @ -18,7 +16,7 @@ export default ({ expressApp }: { expressApp: Application }) => { | |||
|       new Tracing.Integrations.Express({ app: expressApp }), | ||||
|     ], | ||||
|     tracesSampleRate: 0.1, | ||||
|     release: currentVersion, | ||||
|     release: version, | ||||
|   }); | ||||
| 
 | ||||
|   expressApp.use(Sentry.Handlers.requestHandler()); | ||||
|  |  | |||
|  | @ -9,6 +9,7 @@ import ScheduleService from './schedule'; | |||
| import { spawn } from 'child_process'; | ||||
| import SockService from './sock'; | ||||
| import got from 'got'; | ||||
| import { parseContentVersion, parseVersion } from '../config/util'; | ||||
| 
 | ||||
| @Service() | ||||
| export default class SystemService { | ||||
|  | @ -78,14 +79,9 @@ export default class SystemService { | |||
| 
 | ||||
|   public async checkUpdate() { | ||||
|     try { | ||||
|       const versionRegx = /.*export const version = \'(.*)\'\;/; | ||||
|       const logRegx = /.*export const changeLog = \`((.*\n.*)+)\`;/; | ||||
|       const currentVersionContent = await parseVersion(config.versionFile); | ||||
| 
 | ||||
|       const currentVersionFile = fs.readFileSync(config.versionFile, 'utf8'); | ||||
|       const currentVersion = currentVersionFile.match(versionRegx)![1]; | ||||
| 
 | ||||
|       let lastVersion = ''; | ||||
|       let lastLog = ''; | ||||
|       let lastVersionContent; | ||||
|       try { | ||||
|         const result = await got.get( | ||||
|           `${config.lastVersionFile}?t=${Date.now()}`, | ||||
|  | @ -93,19 +89,23 @@ export default class SystemService { | |||
|             timeout: 30000, | ||||
|           }, | ||||
|         ); | ||||
|         const lastVersionFileContent = result.body; | ||||
|         lastVersion = lastVersionFileContent.match(versionRegx)![1]; | ||||
|         lastLog = lastVersionFileContent.match(logRegx) | ||||
|           ? lastVersionFileContent.match(logRegx)![1] | ||||
|           : ''; | ||||
|         lastVersionContent = await parseContentVersion(result.body); | ||||
|       } catch (error) {} | ||||
| 
 | ||||
|       if (!lastVersionContent) { | ||||
|         lastVersionContent = currentVersionContent; | ||||
|       } | ||||
| 
 | ||||
|       return { | ||||
|         code: 200, | ||||
|         data: { | ||||
|           hasNewVersion: this.checkHasNewVersion(currentVersion, lastVersion), | ||||
|           lastVersion, | ||||
|           lastLog, | ||||
|           hasNewVersion: this.checkHasNewVersion( | ||||
|             currentVersionContent.version, | ||||
|             lastVersionContent.version, | ||||
|           ), | ||||
|           lastVersion: lastVersionContent.version, | ||||
|           lastLog: lastVersionContent.changeLog, | ||||
|           lastLogLink: lastVersionContent.changeLogLink, | ||||
|         }, | ||||
|       }; | ||||
|     } catch (error: any) { | ||||
|  |  | |||
|  | @ -69,6 +69,7 @@ | |||
|     "got": "^11.8.2", | ||||
|     "hpagent": "^0.1.2", | ||||
|     "iconv-lite": "^0.6.3", | ||||
|     "js-yaml": "^4.1.0", | ||||
|     "jsonwebtoken": "^8.5.1", | ||||
|     "lodash": "^4.17.21", | ||||
|     "multer": "^1.4.4", | ||||
|  | @ -97,6 +98,7 @@ | |||
|     "@types/cors": "^2.8.12", | ||||
|     "@types/express": "^4.17.13", | ||||
|     "@types/express-jwt": "^6.0.4", | ||||
|     "@types/js-yaml": "^4.0.5", | ||||
|     "@types/jsonwebtoken": "^8.5.8", | ||||
|     "@types/lodash": "^4.14.185", | ||||
|     "@types/multer": "^1.4.7", | ||||
|  |  | |||
|  | @ -13,6 +13,7 @@ specifiers: | |||
|   '@types/cors': ^2.8.12 | ||||
|   '@types/express': ^4.17.13 | ||||
|   '@types/express-jwt': ^6.0.4 | ||||
|   '@types/js-yaml': ^4.0.5 | ||||
|   '@types/jsonwebtoken': ^8.5.8 | ||||
|   '@types/lodash': ^4.14.185 | ||||
|   '@types/multer': ^1.4.7 | ||||
|  | @ -49,6 +50,7 @@ specifiers: | |||
|   got: ^11.8.2 | ||||
|   hpagent: ^0.1.2 | ||||
|   iconv-lite: ^0.6.3 | ||||
|   js-yaml: ^4.1.0 | ||||
|   jsonwebtoken: ^8.5.1 | ||||
|   lint-staged: ^13.0.3 | ||||
|   lodash: ^4.17.21 | ||||
|  | @ -107,6 +109,7 @@ dependencies: | |||
|   got: 11.8.5 | ||||
|   hpagent: 0.1.2 | ||||
|   iconv-lite: 0.6.3 | ||||
|   js-yaml: 4.1.0 | ||||
|   jsonwebtoken: 8.5.1 | ||||
|   lodash: 4.17.21 | ||||
|   multer: 1.4.4 | ||||
|  | @ -135,6 +138,7 @@ devDependencies: | |||
|   '@types/cors': 2.8.12 | ||||
|   '@types/express': 4.17.14 | ||||
|   '@types/express-jwt': 6.0.4 | ||||
|   '@types/js-yaml': 4.0.5 | ||||
|   '@types/jsonwebtoken': 8.5.9 | ||||
|   '@types/lodash': 4.14.185 | ||||
|   '@types/multer': 1.4.7 | ||||
|  | @ -2630,6 +2634,10 @@ packages: | |||
|       '@types/istanbul-lib-report': 3.0.0 | ||||
|     dev: true | ||||
| 
 | ||||
|   /@types/js-yaml/4.0.5: | ||||
|     resolution: {integrity: sha512-FhpRzf927MNQdRZP0J5DLIdTXhjLYzeUTmLAu69mnVksLH9CJY3IuSeEgbKUki7GQZm0WqDkGzyxju2EZGD2wA==} | ||||
|     dev: true | ||||
| 
 | ||||
|   /@types/json-schema/7.0.11: | ||||
|     resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==} | ||||
|     dev: true | ||||
|  | @ -3841,7 +3849,6 @@ packages: | |||
| 
 | ||||
|   /argparse/2.0.1: | ||||
|     resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} | ||||
|     dev: true | ||||
| 
 | ||||
|   /aria-hidden/1.2.1_jobltc72ducwijlk5r742icaw4: | ||||
|     resolution: {integrity: sha512-PN344VAf9j1EAi+jyVHOJ8XidQdPVssGco39eNcsGdM4wcsILtxrKLkbuiMfLWYROK1FjRQasMWCBttrhjnr6A==} | ||||
|  | @ -7994,7 +8001,6 @@ packages: | |||
|     hasBin: true | ||||
|     dependencies: | ||||
|       argparse: 2.0.1 | ||||
|     dev: true | ||||
| 
 | ||||
|   /jsbn/0.1.1: | ||||
|     resolution: {integrity: sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==} | ||||
|  |  | |||
|  | @ -5,14 +5,14 @@ const envFound = dotenv.config(); | |||
| const accessKey = process.env.QINIU_AK; | ||||
| const secretKey = process.env.QINIU_SK; | ||||
| const mac = new qiniu.auth.digest.Mac(accessKey, secretKey); | ||||
| const key = 'version.ts'; | ||||
| const key = 'version.yaml'; | ||||
| const options = { | ||||
|   scope: `${process.env.QINIU_SCOPE}:${key}`, | ||||
| }; | ||||
| const putPolicy = new qiniu.rs.PutPolicy(options); | ||||
| const uploadToken = putPolicy.uploadToken(mac); | ||||
| 
 | ||||
| const localFile = 'src/version.ts'; | ||||
| const localFile = 'version.yaml'; | ||||
| const config = new qiniu.conf.Config({ zone: qiniu.zone.Zone_z1 }); | ||||
| const formUploader = new qiniu.form_up.FormUploader(config); | ||||
| const putExtra = new qiniu.form_up.PutExtra( | ||||
|  |  | |||
|  | @ -13,10 +13,6 @@ git push | |||
| echo -e "更新cdn文件" | ||||
| ts-node sample/tool.ts | ||||
| 
 | ||||
| string=$(cat src/version.ts | grep "version" | egrep "[^\']*" -o | egrep "\d\.*") | ||||
| version="v$string" | ||||
| echo -e "当前版本$version" | ||||
| 
 | ||||
| echo -e "删除已经存在的本地tag" | ||||
| git tag -d "$version" &>/dev/null | ||||
| 
 | ||||
|  |  | |||
|  | @ -26,33 +26,6 @@ diff_cron() { | |||
|   fi | ||||
| } | ||||
| 
 | ||||
| ## 检测配置文件版本 | ||||
| detect_config_version() { | ||||
|   ## 识别出两个文件的版本号 | ||||
|   ver_config_sample=$(grep " Version: " $file_config_sample | perl -pe "s|.+v((\d+\.?){3})|\1|") | ||||
|   [[ -f $file_config_user ]] && ver_config_user=$(grep " Version: " $file_config_user | perl -pe "s|.+v((\d+\.?){3})|\1|") | ||||
| 
 | ||||
|   ## 删除旧的发送记录文件 | ||||
|   [[ -f $send_mark ]] && [[ $(cat $send_mark) != $ver_config_sample ]] && rm -f $send_mark | ||||
| 
 | ||||
|   ## 识别出更新日期和更新内容 | ||||
|   update_date=$(grep " Date: " $file_config_sample | awk -F ": " '{print $2}') | ||||
|   update_content=$(grep " Update Content: " $file_config_sample | awk -F ": " '{print $2}') | ||||
| 
 | ||||
|   ## 如果是今天,并且版本号不一致,则发送通知 | ||||
|   if [[ -f $file_config_user ]] && [[ $ver_config_user != $ver_config_sample ]] && [[ $update_date == $(date "+%Y-%m-%d") ]]; then | ||||
|     if [[ ! -f $send_mark ]]; then | ||||
|       local notify_title="配置文件更新通知" | ||||
|       local notify_content="更新日期: $update_date\n用户版本: $ver_config_user\n新的版本: $ver_config_sample\n更新内容: $update_content\n更新说明: 如需使用新功能请对照config.sample.sh,将相关新参数手动增加到你自己的config.sh中,否则请无视本消息。本消息只在该新版本配置文件更新当天发送一次。\n" | ||||
|       echo -e $notify_content | ||||
|       notify_api "$notify_title" "$notify_content" | ||||
|       [[ $? -eq 0 ]] && echo $ver_config_sample >$send_mark | ||||
|     fi | ||||
|   else | ||||
|     [[ -f $send_mark ]] && rm -f $send_mark | ||||
|   fi | ||||
| } | ||||
| 
 | ||||
| ## 输出是否有新的或失效的定时任务,$1:新的或失效的任务清单文件路径,$2:新/失效 | ||||
| output_list_add_drop() { | ||||
|   local list=$1 | ||||
|  | @ -266,7 +239,6 @@ update_qinglong() { | |||
|   if [[ $exit_status -eq 0 ]]; then | ||||
|     echo -e "\n更新青龙源文件成功...\n" | ||||
|     cp -f $file_config_sample $dir_config/config.sample.sh | ||||
|     detect_config_version | ||||
|     update_depend | ||||
| 
 | ||||
|     [[ -f $dir_root/package.json ]] && ql_depend_new=$(cat $dir_root/package.json) | ||||
|  | @ -291,8 +263,6 @@ update_qinglong_static() { | |||
|   fi | ||||
|   if [[ $exit_status -eq 0 ]]; then | ||||
|     echo -e "\n更新青龙静态资源成功...\n" | ||||
|     local static_version=$(cat $dir_root/src/version.ts | perl -pe "s|.*\'(.*)\';\.*|\1|" | head -1) | ||||
|     echo -e "\n当前版本 $static_version...\n" | ||||
| 
 | ||||
|     rm -rf $dir_static/* | ||||
|     cp -rf $ql_static_repo/* $dir_static | ||||
|  |  | |||
|  | @ -13,7 +13,6 @@ import config from '@/utils/config'; | |||
| import { request } from '@/utils/http'; | ||||
| import './index.less'; | ||||
| import vhCheck from 'vh-check'; | ||||
| import { version, changeLogLink, changeLog } from '../version'; | ||||
| import { useCtx, useTheme } from '@/utils/hooks'; | ||||
| import { | ||||
|   message, | ||||
|  | @ -52,6 +51,8 @@ interface TSystemInfo { | |||
|   lastCommitId: string; | ||||
|   lastCommitTime: number; | ||||
|   version: string; | ||||
|   changeLog: string; | ||||
|   changeLogLink: string; | ||||
| } | ||||
| 
 | ||||
| export default function () { | ||||
|  | @ -89,6 +90,7 @@ export default function () { | |||
|           if (!data.isInitialized) { | ||||
|             history.push('/initialization'); | ||||
|           } else { | ||||
|             init(data.version); | ||||
|             getUser(); | ||||
|           } | ||||
|         } | ||||
|  | @ -143,7 +145,6 @@ export default function () { | |||
| 
 | ||||
|   useEffect(() => { | ||||
|     vhCheck(); | ||||
|     init(); | ||||
| 
 | ||||
|     const _theme = localStorage.getItem('qinglong_dark_theme') || 'auto'; | ||||
|     if (typeof window === 'undefined') return; | ||||
|  | @ -269,7 +270,7 @@ export default function () { | |||
|         <> | ||||
|           <span style={{ fontSize: 16 }}>控制面板</span> | ||||
|           <a | ||||
|             href={changeLogLink} | ||||
|             href={systemInfo?.changeLogLink} | ||||
|             target="_blank" | ||||
|             rel="noopener noreferrer" | ||||
|             onClick={(e) => { | ||||
|  | @ -289,7 +290,7 @@ export default function () { | |||
|                     letterSpacing: isQQBrowser ? -2 : 0, | ||||
|                   }} | ||||
|                 > | ||||
|                   v{version} | ||||
|                   v{systemInfo?.version} | ||||
|                 </span> | ||||
|               </Badge> | ||||
|             </Tooltip> | ||||
|  |  | |||
|  | @ -40,7 +40,7 @@ const About = ({ systemInfo }: { systemInfo: SharedContext['systemInfo'] }) => { | |||
|           </Descriptions.Item> | ||||
|           <Descriptions.Item label="更新日志" span={3}> | ||||
|             <Link | ||||
|               href={`https://qn.whyour.cn/version.ts?t=${Date.now()}`} | ||||
|               href={`https://qn.whyour.cn/version.yaml?t=${Date.now()}`} | ||||
|               target="_blank" | ||||
|             > | ||||
|               查看 | ||||
|  |  | |||
|  | @ -2,11 +2,10 @@ import React, { useEffect, useState, useRef } from 'react'; | |||
| import { Statistic, Modal, Tag, Button, Spin, message } from 'antd'; | ||||
| import { request } from '@/utils/http'; | ||||
| import config from '@/utils/config'; | ||||
| import { version } from '../../version'; | ||||
| 
 | ||||
| const { Countdown } = Statistic; | ||||
| 
 | ||||
| const CheckUpdate = ({ socketMessage }: any) => { | ||||
| const CheckUpdate = ({ socketMessage, systemInfo }: any) => { | ||||
|   const [updateLoading, setUpdateLoading] = useState(false); | ||||
|   const [value, setValue] = useState(''); | ||||
|   const modalRef = useRef<any>(); | ||||
|  | @ -23,7 +22,7 @@ const CheckUpdate = ({ socketMessage }: any) => { | |||
|           if (data.hasNewVersion) { | ||||
|             showConfirmUpdateModal(data); | ||||
|           } else { | ||||
|             showForceUpdateModal(); | ||||
|             showForceUpdateModal(data); | ||||
|           } | ||||
|         } | ||||
|       }) | ||||
|  | @ -36,7 +35,7 @@ const CheckUpdate = ({ socketMessage }: any) => { | |||
|       }); | ||||
|   }; | ||||
| 
 | ||||
|   const showForceUpdateModal = () => { | ||||
|   const showForceUpdateModal = (data: any) => { | ||||
|     Modal.confirm({ | ||||
|       width: 500, | ||||
|       title: '更新', | ||||
|  | @ -44,7 +43,7 @@ const CheckUpdate = ({ socketMessage }: any) => { | |||
|         <> | ||||
|           <div>已经是最新版了!</div> | ||||
|           <div style={{ fontSize: 12, fontWeight: 400, marginTop: 5 }}> | ||||
|             青龙 {version} 是目前检测到的最新可用版本了。 | ||||
|             青龙 {data.lastVersion} 是目前检测到的最新可用版本了。 | ||||
|           </div> | ||||
|         </> | ||||
|       ), | ||||
|  | @ -70,14 +69,13 @@ const CheckUpdate = ({ socketMessage }: any) => { | |||
|         <> | ||||
|           <div>更新可用</div> | ||||
|           <div style={{ fontSize: 12, fontWeight: 400, marginTop: 5 }}> | ||||
|             新版本{lastVersion}可用。你使用的版本为{version}。 | ||||
|             新版本 {lastVersion} 可用,你使用的版本为 {systemInfo.version}。 | ||||
|           </div> | ||||
|         </> | ||||
|       ), | ||||
|       content: ( | ||||
|         <pre | ||||
|           style={{ | ||||
|             paddingTop: 15, | ||||
|             fontSize: 12, | ||||
|             fontWeight: 400, | ||||
|           }} | ||||
|  |  | |||
|  | @ -416,7 +416,10 @@ const Setting = () => { | |||
|                   </Input.Group> | ||||
|                 </Form.Item> | ||||
|                 <Form.Item label="检查更新" name="update"> | ||||
|                   <CheckUpdate socketMessage={socketMessage} /> | ||||
|                   <CheckUpdate | ||||
|                     systemInfo={systemInfo} | ||||
|                     socketMessage={socketMessage} | ||||
|                   /> | ||||
|                 </Form.Item> | ||||
|               </Form> | ||||
|             ), | ||||
|  |  | |||
|  | @ -1,9 +1,8 @@ | |||
| import * as Sentry from '@sentry/react'; | ||||
| import { Integrations } from '@sentry/tracing'; | ||||
| import { loader } from '@monaco-editor/react'; | ||||
| import { version } from '../version'; | ||||
| 
 | ||||
| export function init() { | ||||
| export function init(version: string) { | ||||
|   // sentry监控 init
 | ||||
|   Sentry.init({ | ||||
|     dsn: 'https://3406424fb1dc4813a62d39e844a9d0ac@o1098464.ingest.sentry.io/6122818', | ||||
|  |  | |||
|  | @ -1,10 +0,0 @@ | |||
| export const version = '2.15.3'; | ||||
| export const changeLogLink = 'https://t.me/jiao_long/354'; | ||||
| export const changeLog = `2.15.3 版本说明
 | ||||
| 1. 任务视图增加标签筛选 | ||||
| 2. 修改默认镜像python版本为3.10 | ||||
| 3. 修复notify.js中智能微秘书,感谢 https://github.com/CoolClash
 | ||||
| 4. 修复超时任务日志打印 | ||||
| 5. 修复调试脚本页保存脚本父目录 | ||||
| 6. 其他优化 | ||||
| `;
 | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 whyour
						whyour