From 4e6019ec613e296f6c6bf486c7d7f878a3537f41 Mon Sep 17 00:00:00 2001 From: Codex Bot Date: Mon, 21 Sep 2026 16:01:26 +0800 Subject: [PATCH] refactor: migrate mini program to TypeScript --- README.md | 5 +++-- miniprogram/app.js | 7 ------ miniprogram/app.ts | 17 +++++++++++++++ miniprogram/config.js | 2 -- miniprogram/config.ts | 1 + miniprogram/pages/activity/index.js | 2 -- miniprogram/pages/activity/index.ts | 23 +++++++++++++++++++ miniprogram/pages/index/index.js | 2 -- miniprogram/pages/index/index.ts | 34 +++++++++++++++++++++++++++++ miniprogram/pages/login/index.js | 1 - miniprogram/pages/login/index.ts | 1 + miniprogram/pages/profile/index.js | 1 - miniprogram/pages/profile/index.ts | 12 ++++++++++ miniprogram/tsconfig.json | 13 +++++++++++ miniprogram/types/models.ts | 34 +++++++++++++++++++++++++++++ miniprogram/typings/index.d.ts | 12 ++++++++++ miniprogram/utils/api.js | 4 ---- miniprogram/utils/api.ts | 31 ++++++++++++++++++++++++++ package-lock.json | 27 ++++++++++++++++++++++- package.json | 3 +-- project.config.json | 2 +- 21 files changed, 209 insertions(+), 25 deletions(-) delete mode 100644 miniprogram/app.js create mode 100644 miniprogram/app.ts delete mode 100644 miniprogram/config.js create mode 100644 miniprogram/config.ts delete mode 100644 miniprogram/pages/activity/index.js create mode 100644 miniprogram/pages/activity/index.ts delete mode 100644 miniprogram/pages/index/index.js create mode 100644 miniprogram/pages/index/index.ts delete mode 100644 miniprogram/pages/login/index.js create mode 100644 miniprogram/pages/login/index.ts delete mode 100644 miniprogram/pages/profile/index.js create mode 100644 miniprogram/pages/profile/index.ts create mode 100644 miniprogram/tsconfig.json create mode 100644 miniprogram/types/models.ts create mode 100644 miniprogram/typings/index.d.ts delete mode 100644 miniprogram/utils/api.js create mode 100644 miniprogram/utils/api.ts diff --git a/README.md b/README.md index f0e54dc..5bb138a 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ ## 目录 -- `miniprogram/`:原生微信小程序 +- `miniprogram/`:原生微信小程序(TypeScript + WXML + WXSS) - `server/`:Node.js API、管理后台和数据库迁移 - `deploy/`:Docker Compose 生产部署 - `.gitea/workflows/`:Gitea Actions 测试及部署 @@ -17,7 +17,8 @@ 3. 将 `miniprogram/config.js` 中的 `apiBaseUrl` 改为已加入微信后台 request 合法域名的 HTTPS 地址。 4. 使用微信开发者工具打开仓库根目录。 +执行 `npm run check` 会同时检查后端 JavaScript 语法和小程序 TypeScript 类型。 + 管理后台位于 `https://你的域名/admin/`,登录凭据为环境变量 `ADMIN_TOKEN`。 完整部署及微信平台配置见 [docs/deployment.md](docs/deployment.md)。 - diff --git a/miniprogram/app.js b/miniprogram/app.js deleted file mode 100644 index caf0639..0000000 --- a/miniprogram/app.js +++ /dev/null @@ -1,7 +0,0 @@ -const api = require('./utils/api') -App({ - globalData: { user: wx.getStorageSync('user') || null }, - onLaunch() { this.loginPromise = this.login() }, - login() { return new Promise((resolve, reject) => wx.login({ success: ({ code }) => api.request('/api/auth/wechat', { method: 'POST', data: { code } }).then(({ token, user }) => { wx.setStorageSync('token', token); wx.setStorageSync('user', user); this.globalData.user = user; resolve(user) }).catch(reject), fail: reject })) }, - ensureLogin() { return this.loginPromise || this.login() } -}) diff --git a/miniprogram/app.ts b/miniprogram/app.ts new file mode 100644 index 0000000..4c7980a --- /dev/null +++ b/miniprogram/app.ts @@ -0,0 +1,17 @@ +import { request } from './utils/api' + +App({ + globalData: { user: wx.getStorageSync('user') || null }, + onLaunch() { this.loginPromise = this.login() }, + login() { + return new Promise((resolve, reject) => wx.login({ + success: ({ code }) => request<{ token: string; user: CoffeeChatUser }>('/api/auth/wechat', { method: 'POST', data: { code } }) + .then(({ token, user }) => { + wx.setStorageSync('token', token); wx.setStorageSync('user', user) + this.globalData.user = user; resolve(user) + }).catch(reject), + fail: reject + })) + }, + ensureLogin() { return this.loginPromise || this.login() } +}) diff --git a/miniprogram/config.js b/miniprogram/config.js deleted file mode 100644 index 91f68a9..0000000 --- a/miniprogram/config.js +++ /dev/null @@ -1,2 +0,0 @@ -module.exports = { apiBaseUrl: 'https://coffeechat.example.com' } - diff --git a/miniprogram/config.ts b/miniprogram/config.ts new file mode 100644 index 0000000..0f2fafc --- /dev/null +++ b/miniprogram/config.ts @@ -0,0 +1 @@ +export const apiBaseUrl = 'https://coffeechat.example.com' diff --git a/miniprogram/pages/activity/index.js b/miniprogram/pages/activity/index.js deleted file mode 100644 index bae22b9..0000000 --- a/miniprogram/pages/activity/index.js +++ /dev/null @@ -1,2 +0,0 @@ -const api=require('../../utils/api');const app=getApp(); -Page({data:{id:'',activity:null,user:null,joined:false,purpose:'',showPurpose:false,submitting:false},onLoad({id}){this.setData({id,user:app.globalData.user||wx.getStorageSync('user')});app.ensureLogin().then(user=>{this.setData({user});this.load()}).catch(()=>this.load())},onShow(){if(this.data.activity)this.load()},async load(){try{const activity=await api.request(`/api/activities/${this.data.id}`);const mine=activity.participants.find(p=>this.data.user&&p.id===this.data.user.id);this.setData({activity,joined:!!mine,purpose:mine?mine.purpose:''})}catch(e){wx.showToast({title:e.message,icon:'none'})}},preview(e){const urls=this.data.activity.images.map(x=>x.url);wx.previewImage({current:e.currentTarget.dataset.url,urls})},editPurpose(){this.setData({showPurpose:true})},purposeInput(e){this.setData({purpose:e.detail.value})},closePurpose(){this.setData({showPurpose:false})},async savePurpose(){this.setData({submitting:true});try{await api.request(`/api/activities/${this.data.id}/participations/me`,{method:'PUT',data:{purpose:this.data.purpose}});this.setData({showPurpose:false});await this.load();wx.showToast({title:'已加入'})}catch(e){wx.showToast({title:e.message,icon:'none'})}finally{this.setData({submitting:false})}},leave(){wx.showModal({title:'退出活动?',content:'你的参与目的也会被移除',success:async r=>{if(r.confirm){await api.request(`/api/activities/${this.data.id}/participations/me`,{method:'DELETE'});this.load()}}})},openGroup(e){wx.previewImage({urls:[e.currentTarget.dataset.url]})},submitGroup(){wx.chooseMedia({count:1,mediaType:['image'],success:async r=>{wx.showLoading({title:'上传中'});try{const file=await api.upload(r.tempFiles[0].tempFilePath);await api.request(`/api/activities/${this.data.id}/participations/groups`,{method:'POST',data:{name:`${this.data.activity.title}交流群`,qrImageUrl:file.url,note:'用户提交,待管理员核验'}});wx.showToast({title:'已提交审核'})}catch(e){wx.showToast({title:e.message,icon:'none'})}finally{wx.hideLoading()}}})}}) diff --git a/miniprogram/pages/activity/index.ts b/miniprogram/pages/activity/index.ts new file mode 100644 index 0000000..d43cea9 --- /dev/null +++ b/miniprogram/pages/activity/index.ts @@ -0,0 +1,23 @@ +import { request, upload } from '../../utils/api' +import type { Activity } from '../../types/models' + +const app = getApp() +interface ActivityData { id: string; activity: Activity | null; user: CoffeeChatUser | null; joined: boolean; purpose: string; showPurpose: boolean; submitting: boolean } + +Page({ + data: { id: '', activity: null, user: null, joined: false, purpose: '', showPurpose: false, submitting: false }, + onLoad({ id }) { this.setData({ id, user: app.globalData.user || wx.getStorageSync('user') }); app.ensureLogin().then((user) => { this.setData({ user }); void this.load() }).catch(() => this.load()) }, + onShow() { if (this.data.activity) void this.load() }, + async load() { + try { const activity = await request(`/api/activities/${this.data.id}`); const mine = activity.participants.find((person) => person.id === this.data.user?.id); this.setData({ activity, joined: Boolean(mine), purpose: mine?.purpose || '' }) } + catch (error) { wx.showToast({ title: error instanceof Error ? error.message : '加载失败', icon: 'none' }) } + }, + preview(event: WechatMiniprogram.TouchEvent) { const activity = this.data.activity; if (activity) wx.previewImage({ current: event.currentTarget.dataset.url, urls: activity.images.map((image) => image.url) }) }, + editPurpose() { this.setData({ showPurpose: true }) }, + purposeInput(event: WechatMiniprogram.CustomEvent<{ value: string }>) { this.setData({ purpose: event.detail.value }) }, + closePurpose() { this.setData({ showPurpose: false }) }, + async savePurpose() { this.setData({ submitting: true }); try { await request(`/api/activities/${this.data.id}/participations/me`, { method: 'PUT', data: { purpose: this.data.purpose } }); this.setData({ showPurpose: false }); await this.load(); wx.showToast({ title: '已加入' }) } catch (error) { wx.showToast({ title: error instanceof Error ? error.message : '提交失败', icon: 'none' }) } finally { this.setData({ submitting: false }) } }, + leave() { wx.showModal({ title: '退出活动?', content: '你的参与目的也会被移除', success: ({ confirm }) => { if (confirm) void request(`/api/activities/${this.data.id}/participations/me`, { method: 'DELETE' }).then(() => this.load()) } }) }, + openGroup(event: WechatMiniprogram.TouchEvent) { wx.previewImage({ urls: [event.currentTarget.dataset.url] }) }, + submitGroup() { wx.chooseMedia({ count: 1, mediaType: ['image'], success: async ({ tempFiles }) => { wx.showLoading({ title: '上传中' }); try { const file = await upload(tempFiles[0].tempFilePath); await request(`/api/activities/${this.data.id}/participations/groups`, { method: 'POST', data: { name: `${this.data.activity?.title || '活动'}交流群`, qrImageUrl: file.url, note: '用户提交,待管理员核验' } }); wx.showToast({ title: '已提交审核' }) } catch (error) { wx.showToast({ title: error instanceof Error ? error.message : '上传失败', icon: 'none' }) } finally { wx.hideLoading() } } }) } +}) diff --git a/miniprogram/pages/index/index.js b/miniprogram/pages/index/index.js deleted file mode 100644 index 427faeb..0000000 --- a/miniprogram/pages/index/index.js +++ /dev/null @@ -1,2 +0,0 @@ -const api = require('../../utils/api') -Page({data:{activities:[],exhibitions:[],tags:[],exhibitionIndex:0,selectedTag:'',time:'available',loading:true},onLoad(){this.loadMeta()},onShow(){if(this.data.exhibitions.length)this.loadActivities()},onPullDownRefresh(){this.loadActivities().finally(wx.stopPullDownRefresh)},async loadMeta(){try{const data=await api.request('/api/activities/meta');this.setData({exhibitions:[{id:'',name:'全部会展'}].concat(data.exhibitions),tags:data.tags});await this.loadActivities()}catch(e){this.fail(e)}},async loadActivities(){this.setData({loading:true});const exhibition=this.data.exhibitions[this.data.exhibitionIndex];const qs=[`time=${this.data.time}`];if(exhibition&&exhibition.id)qs.push(`exhibitionId=${exhibition.id}`);if(this.data.selectedTag)qs.push(`tagId=${this.data.selectedTag}`);try{const activities=await api.request(`/api/activities?${qs.join('&')}`);this.setData({activities,loading:false})}catch(e){this.fail(e)}},changeExhibition(e){this.setData({exhibitionIndex:Number(e.detail.value)});this.loadActivities()},selectTag(e){this.setData({selectedTag:this.data.selectedTag===e.currentTarget.dataset.id?'':e.currentTarget.dataset.id});this.loadActivities()},setTime(e){this.setData({time:e.currentTarget.dataset.value});this.loadActivities()},open(e){wx.navigateTo({url:`/pages/activity/index?id=${e.currentTarget.dataset.id}`})},fail(e){this.setData({loading:false});wx.showToast({title:e.message||'加载失败',icon:'none'})}}) diff --git a/miniprogram/pages/index/index.ts b/miniprogram/pages/index/index.ts new file mode 100644 index 0000000..064635b --- /dev/null +++ b/miniprogram/pages/index/index.ts @@ -0,0 +1,34 @@ +import { request } from '../../utils/api' +import type { Activity, CatalogMeta, Exhibition, Tag } from '../../types/models' + +interface IndexData { + activities: Activity[]; exhibitions: Exhibition[]; tags: Tag[]; exhibitionIndex: number + selectedTag: string; time: 'upcoming' | 'available'; loading: boolean +} + +Page({ + data: { activities: [], exhibitions: [], tags: [], exhibitionIndex: 0, selectedTag: '', time: 'available', loading: true }, + onLoad() { void this.loadMeta() }, + onShow() { if (this.data.exhibitions.length) void this.loadActivities() }, + onPullDownRefresh() { void this.loadActivities().finally(() => wx.stopPullDownRefresh()) }, + async loadMeta() { + try { + const data = await request('/api/activities/meta') + const all = { id: '', name: '全部会展', venue: '', address: '', startsAt: '', endsAt: '', description: '' } + this.setData({ exhibitions: [all, ...data.exhibitions], tags: data.tags }); await this.loadActivities() + } catch (error) { this.fail(error) } + }, + async loadActivities() { + this.setData({ loading: true }); const exhibition = this.data.exhibitions[this.data.exhibitionIndex] + const query = [`time=${this.data.time}`] + if (exhibition?.id) query.push(`exhibitionId=${encodeURIComponent(exhibition.id)}`) + if (this.data.selectedTag) query.push(`tagId=${encodeURIComponent(this.data.selectedTag)}`) + try { this.setData({ activities: await request(`/api/activities?${query.join('&')}`), loading: false }) } + catch (error) { this.fail(error) } + }, + changeExhibition(event: WechatMiniprogram.CustomEvent<{ value: string }>) { this.setData({ exhibitionIndex: Number(event.detail.value) }); void this.loadActivities() }, + selectTag(event: WechatMiniprogram.TouchEvent) { const id = String(event.currentTarget.dataset.id || ''); this.setData({ selectedTag: this.data.selectedTag === id ? '' : id }); void this.loadActivities() }, + setTime(event: WechatMiniprogram.TouchEvent) { this.setData({ time: event.currentTarget.dataset.value }); void this.loadActivities() }, + open(event: WechatMiniprogram.TouchEvent) { wx.navigateTo({ url: `/pages/activity/index?id=${event.currentTarget.dataset.id}` }) }, + fail(error: unknown) { this.setData({ loading: false }); wx.showToast({ title: error instanceof Error ? error.message : '加载失败', icon: 'none' }) } +}) diff --git a/miniprogram/pages/login/index.js b/miniprogram/pages/login/index.js deleted file mode 100644 index 343d51e..0000000 --- a/miniprogram/pages/login/index.js +++ /dev/null @@ -1 +0,0 @@ -Page({retry(){getApp().login().then(()=>wx.switchTab({url:'/pages/index/index'})).catch(e=>wx.showToast({title:e.message,icon:'none'}))}}) diff --git a/miniprogram/pages/login/index.ts b/miniprogram/pages/login/index.ts new file mode 100644 index 0000000..f460a10 --- /dev/null +++ b/miniprogram/pages/login/index.ts @@ -0,0 +1 @@ +Page({ retry() { getApp().login().then(() => wx.switchTab({ url: '/pages/index/index' })).catch((error: unknown) => wx.showToast({ title: error instanceof Error ? error.message : '登录失败', icon: 'none' })) } }) diff --git a/miniprogram/pages/profile/index.js b/miniprogram/pages/profile/index.js deleted file mode 100644 index 5481631..0000000 --- a/miniprogram/pages/profile/index.js +++ /dev/null @@ -1 +0,0 @@ -const api=require('../../utils/api');const app=getApp();Page({data:{user:null,editing:false,nickname:''},onShow(){app.ensureLogin().then(user=>this.setData({user,nickname:user.nickname})).catch(()=>{})},edit(){this.setData({editing:true})},input(e){this.setData({nickname:e.detail.value})},cancel(){this.setData({editing:false})},async save(){try{const user=await api.request('/api/auth/me',{method:'PATCH',data:{nickname:this.data.nickname,avatarUrl:this.data.user.avatarUrl||''}});wx.setStorageSync('user',user);app.globalData.user=user;this.setData({user,editing:false});wx.showToast({title:'已保存'})}catch(e){wx.showToast({title:e.message,icon:'none'})}},chooseAvatar(e){const avatarUrl=e.detail.avatarUrl;this.setData({'user.avatarUrl':avatarUrl});api.upload(avatarUrl).then(file=>this.setData({'user.avatarUrl':file.url}))}}) diff --git a/miniprogram/pages/profile/index.ts b/miniprogram/pages/profile/index.ts new file mode 100644 index 0000000..540e8f6 --- /dev/null +++ b/miniprogram/pages/profile/index.ts @@ -0,0 +1,12 @@ +import { request, upload } from '../../utils/api' +const app = getApp() + +Page({ + data: { user: null as CoffeeChatUser | null, editing: false, nickname: '' }, + onShow() { app.ensureLogin().then((user) => this.setData({ user, nickname: user.nickname })).catch(() => undefined) }, + edit() { this.setData({ editing: true }) }, + input(event: WechatMiniprogram.CustomEvent<{ value: string }>) { this.setData({ nickname: event.detail.value }) }, + cancel() { this.setData({ editing: false }) }, + async save() { if (!this.data.user) return; try { const user = await request('/api/auth/me', { method: 'PATCH', data: { nickname: this.data.nickname, avatarUrl: this.data.user.avatarUrl || '' } }); wx.setStorageSync('user', user); app.globalData.user = user; this.setData({ user, editing: false }); wx.showToast({ title: '已保存' }) } catch (error) { wx.showToast({ title: error instanceof Error ? error.message : '保存失败', icon: 'none' }) } }, + chooseAvatar(event: WechatMiniprogram.CustomEvent<{ avatarUrl: string }>) { const avatarUrl = event.detail.avatarUrl; this.setData({ 'user.avatarUrl': avatarUrl }); upload(avatarUrl).then((file) => this.setData({ 'user.avatarUrl': file.url })).catch(() => wx.showToast({ title: '头像上传失败', icon: 'none' })) } +}) diff --git a/miniprogram/tsconfig.json b/miniprogram/tsconfig.json new file mode 100644 index 0000000..ba7239c --- /dev/null +++ b/miniprogram/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "strict": true, + "target": "ES2020", + "module": "CommonJS", + "moduleResolution": "Node", + "noEmit": true, + "skipLibCheck": true, + "types": ["miniprogram-api-typings"] + }, + "include": ["app.ts", "pages/**/*.ts", "utils/**/*.ts", "types/**/*.ts", "typings/**/*.d.ts"], + "exclude": ["pages/example/**", "components/**"] +} diff --git a/miniprogram/types/models.ts b/miniprogram/types/models.ts new file mode 100644 index 0000000..a44737a --- /dev/null +++ b/miniprogram/types/models.ts @@ -0,0 +1,34 @@ +export interface Exhibition { + id: string + name: string + venue: string + address: string + startsAt: string + endsAt: string + description: string + coverUrl?: string +} + +export interface Tag { id: string; name: string; color: string } +export interface ActivityImage { id: string; url: string } +export interface Participant extends CoffeeChatUser { purpose: string; joinedAt: string } +export interface ActivityGroup { id: string; name: string; qrImageUrl: string; note: string } + +export interface Activity { + id: string + title: string + description: string + location: string + startsAt: string + endsAt?: string + capacity?: number + status: 'upcoming' | 'active' | 'ended' + exhibition: Exhibition + images: ActivityImage[] + tags: Tag[] + participantCount: number + participants: Participant[] + groups: ActivityGroup[] +} + +export interface CatalogMeta { exhibitions: Exhibition[]; tags: Tag[] } diff --git a/miniprogram/typings/index.d.ts b/miniprogram/typings/index.d.ts new file mode 100644 index 0000000..bfcfdea --- /dev/null +++ b/miniprogram/typings/index.d.ts @@ -0,0 +1,12 @@ +interface CoffeeChatUser { + id: string + nickname: string + avatarUrl?: string +} + +interface IAppOption { + globalData: { user: CoffeeChatUser | null } + loginPromise?: Promise + login(): Promise + ensureLogin(): Promise +} diff --git a/miniprogram/utils/api.js b/miniprogram/utils/api.js deleted file mode 100644 index bd2ac2e..0000000 --- a/miniprogram/utils/api.js +++ /dev/null @@ -1,4 +0,0 @@ -const { apiBaseUrl } = require('../config') -function request(path, options = {}) { return new Promise((resolve, reject) => wx.request({ url: apiBaseUrl + path, method: options.method || 'GET', data: options.data, header: { 'content-type': 'application/json', Authorization: `Bearer ${wx.getStorageSync('token') || ''}` }, success: (res) => res.statusCode >= 200 && res.statusCode < 300 ? resolve(res.data) : reject(new Error(res.data && res.data.error || '网络请求失败')), fail: reject })) } -function upload(filePath) { return new Promise((resolve, reject) => wx.uploadFile({ url: apiBaseUrl + '/api/uploads', filePath, name: 'files', header: { Authorization: `Bearer ${wx.getStorageSync('token') || ''}` }, success: (res) => { const data = JSON.parse(res.data || '{}'); res.statusCode < 300 ? resolve(data.files[0]) : reject(new Error(data.error || '上传失败')) }, fail: reject })) } -module.exports = { request, upload, apiBaseUrl } diff --git a/miniprogram/utils/api.ts b/miniprogram/utils/api.ts new file mode 100644 index 0000000..372aedc --- /dev/null +++ b/miniprogram/utils/api.ts @@ -0,0 +1,31 @@ +import { apiBaseUrl } from '../config' + +interface RequestOptions { method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH'; data?: unknown } +interface UploadResult { url: string } + +export function request(path: string, options: RequestOptions = {}): Promise { + return new Promise((resolve, reject) => wx.request({ + url: apiBaseUrl + path, + method: (options.method || 'GET') as WechatMiniprogram.RequestOption['method'], + data: options.data as WechatMiniprogram.IAnyObject, + header: { 'content-type': 'application/json', Authorization: `Bearer ${wx.getStorageSync('token') || ''}` }, + success: (response) => response.statusCode >= 200 && response.statusCode < 300 + ? resolve(response.data as T) + : reject(new Error((response.data as { error?: string })?.error || '网络请求失败')), + fail: reject + })) +} + +export function upload(filePath: string): Promise { + return new Promise((resolve, reject) => wx.uploadFile({ + url: apiBaseUrl + '/api/uploads', filePath, name: 'files', + header: { Authorization: `Bearer ${wx.getStorageSync('token') || ''}` }, + success: (response) => { + const data = JSON.parse(response.data || '{}') as { files?: UploadResult[]; error?: string } + response.statusCode < 300 && data.files?.[0] ? resolve(data.files[0]) : reject(new Error(data.error || '上传失败')) + }, + fail: reject + })) +} + +export { apiBaseUrl } diff --git a/package-lock.json b/package-lock.json index 3c766e5..ef3a103 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,7 +7,11 @@ "name": "coffeechat", "workspaces": [ "server" - ] + ], + "devDependencies": { + "miniprogram-api-typings": "^5.0.0", + "typescript": "^5.9.2" + } }, "node_modules/accepts": { "version": "2.0.0", @@ -667,6 +671,13 @@ "url": "https://opencollective.com/express" } }, + "node_modules/miniprogram-api-typings": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/miniprogram-api-typings/-/miniprogram-api-typings-5.2.3.tgz", + "integrity": "sha512-KVcNSfR2VmRtz35rxkjLxE92HlsBnbT6NsKyTcDX3ebbTKAsAiTOFO1mRM82Xbe848dnEYqNGzaD48LMEvGytw==", + "dev": true, + "license": "MIT" + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -1256,6 +1267,20 @@ "url": "https://opencollective.com/express" } }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", diff --git a/package.json b/package.json index 7dca534..a164354 100644 --- a/package.json +++ b/package.json @@ -1,2 +1 @@ -{"name":"coffeechat","private":true,"workspaces":["server"],"scripts":{"dev":"npm --workspace server run dev","start":"npm --workspace server start","test":"npm --workspace server test","check":"npm --workspace server run check"}} - +{"name":"coffeechat","private":true,"workspaces":["server"],"scripts":{"dev":"npm --workspace server run dev","start":"npm --workspace server start","test":"npm --workspace server test","check":"npm --workspace server run check && npm run check:miniprogram","check:miniprogram":"tsc -p miniprogram/tsconfig.json --noEmit"},"devDependencies":{"miniprogram-api-typings":"^5.0.0","typescript":"^5.9.2"}} diff --git a/project.config.json b/project.config.json index be0b0d3..21ea70c 100644 --- a/project.config.json +++ b/project.config.json @@ -39,7 +39,7 @@ "minifyWXML": true, "localPlugins": false, "disableUseStrict": false, - "useCompilerPlugins": false, + "useCompilerPlugins": ["typescript"], "condition": false, "swc": false, "disableSWC": true