Author SHA1 Message Date
CodeBuddy 3ce6edc9a1 feat: 存储空间管理、虚拟支付接入与容量守卫
- 新增存储空间管理:会员套餐配置、用户容量/到期管理、后台支付记录查询
- 接入个人主体小程序虚拟支付:下单/发货推送/兜底查单(query_order)
- 修复 adminStorageUsers 等接口鉴权、out_trade_no 长度、前端 requestVirtualPayment 参数
- 前端上传前容量预检,超容引导升级无限空间
- 我的页会员卡片展示「无限空间」与已用容量/到期时间
- 后台「存储空间管理」新增支付记录标签页
2026-10-26 23:07:09 +08:00
CodeBuddy 0f5dc01674 更新最新代码 2026-10-26 17:32:47 +08:00
23 changed files with 161 additions and 252 deletions
-2
View File
@@ -7,8 +7,6 @@ run/
# 本地配置(含密钥,不入库) # 本地配置(含密钥,不入库)
config.yaml config.yaml
# 生产部署配置模板(含数据库密码,不入库;部署时复制到服务器后按需修改)
deploy/linux/config.prod.yaml
# 依赖与构建产物 # 依赖与构建产物
node_modules/ node_modules/
-10
View File
@@ -1,10 +0,0 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Ignored default folder with query files
/queries/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
-10
View File
@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GoImports">
<option name="excludedPackages">
<array>
<option value="golang.org/x/net/context" />
</array>
</option>
</component>
</project>
-8
View File
@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/past-go.iml" filepath="$PROJECT_DIR$/.idea/past-go.iml" />
</modules>
</component>
</project>
-9
View File
@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="Go" enabled="true" />
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
-18
View File
@@ -1,18 +0,0 @@
# 宝塔网站 → 设置 → 配置文件,把下面整段放到 server { } 内(或改用宝塔“反向代理”UI)
# 作用:把域名的所有请求反代到本地 Go 后端(:8080),由宝塔 Nginx 负责 HTTPS/SSL。
# 允许大文件上传(与 config.yaml 的 max_upload_mb 保持一致,默认 50MB)
client_max_body_size 50m;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# 大文件/慢请求超时,与后端 ReadTimeout 对应
proxy_connect_timeout 60s;
proxy_read_timeout 180s;
proxy_send_timeout 180s;
}
-21
View File
@@ -1,21 +0,0 @@
[Unit]
Description=past-go backend service
After=network.target mysql.service
Wants=mysql.service
[Service]
Type=simple
# 运行用户:宝塔默认站点用户为 www,需对该用户有 data_dir/uploads 写权限
User=www
Group=www
# 改为你实际上传二进制与 config.yaml 的目录
WorkingDirectory=/www/wwwroot/past
ExecStart=/www/wwwroot/past/past-server -config /www/wwwroot/past/config.yaml
Restart=always
RestartSec=3
# 标准输出/错误会进 journalctl;程序自身也会写 data/go-server.log
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
-1
View File
@@ -114,7 +114,6 @@ func adminStatsDetail(c *httpapi.Ctx) error {
"date_contents_total": total, "date_contents_total": total,
"total_users": tableCount(c, "users"), "total_users": tableCount(c, "users"),
"total_couples": tableCount(c, "couples"), "total_couples": tableCount(c, "couples"),
"total_storage_used": allStorageUsedBytes(),
}) })
} }
-36
View File
@@ -9,7 +9,6 @@ import (
"path/filepath" "path/filepath"
"sort" "sort"
"strings" "strings"
"sync"
"time" "time"
"past/internal/config" "past/internal/config"
@@ -100,41 +99,6 @@ func dirSize(root string) int64 {
return total return total
} }
// storageUsedTotalCache 缓存全站已用存储总量,避免后台统计页频繁整目录遍历。
var storageUsedTotalCache = struct {
sync.RWMutex
bytes int64
at time.Time
}{}
// allStorageUsedBytes 统计存储目录所有文件占用字节数,即全站所有用户已使用的存储空间总量。
// 注意:按文件系统实际占用计算(情侣共享空间只计一次),更准确反映磁盘消耗。结果缓存 60 秒。
func allStorageUsedBytes() int64 {
storageUsedTotalCache.RLock()
if !storageUsedTotalCache.at.IsZero() && time.Since(storageUsedTotalCache.at) < time.Minute {
v := storageUsedTotalCache.bytes
storageUsedTotalCache.RUnlock()
return v
}
storageUsedTotalCache.RUnlock()
root := up.Dir
var total int64
if root != "" {
_ = filepath.Walk(root, func(_ string, info os.FileInfo, err error) error {
if err == nil && info != nil && !info.IsDir() {
total += info.Size()
}
return nil
})
}
storageUsedTotalCache.Lock()
storageUsedTotalCache.bytes = total
storageUsedTotalCache.at = time.Now()
storageUsedTotalCache.Unlock()
return total
}
// storageUsedBytes 统计当前用户(或其情侣空间)已用存储字节数。 // storageUsedBytes 统计当前用户(或其情侣空间)已用存储字节数。
// 组成:情侣空间共享文件(couples/{space})+ 相关用户(本人,或情侣双方)的头像(avatars/{user_id})与个人上传文件(users/{id})。 // 组成:情侣空间共享文件(couples/{space})+ 相关用户(本人,或情侣双方)的头像(avatars/{user_id})与个人上传文件(users/{id})。
func storageUsedBytes(c *httpapi.Ctx, uid, coupleID int64) int64 { func storageUsedBytes(c *httpapi.Ctx, uid, coupleID int64) int64 {
+3 -3
View File
@@ -1,3 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 64 64"> <svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 64 64">
<text x="50%" y="50%" dominant-baseline="central" text-anchor="middle" font-size="52">💗</text> <text x="50%" y="50%" dominant-baseline="central" text-anchor="middle" font-size="52">💗</text>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 194 B

After

Width:  |  Height:  |  Size: 191 B

+14 -24
View File
@@ -28,15 +28,6 @@ const CONTENT_LINK: Record<string, string> = {
timeline: "timeline", diaries: "diary", albums: "album", photos: "photo", songs: "song", checkins: "checkin", checkin_logs: "checkin", timeline: "timeline", diaries: "diary", albums: "album", photos: "photo", songs: "song", checkins: "checkin", checkin_logs: "checkin",
} }
function formatBytes(n?: number): string {
if (!n || n <= 0) return "0 B"
const units = ["B", "KB", "MB", "GB", "TB"]
let i = 0
let v = n
while (v >= 1024 && i < units.length - 1) { v /= 1024; i++ }
return `${v >= 100 || i === 0 ? Math.round(v) : v.toFixed(1)} ${units[i]}`
}
export default function Dashboard() { export default function Dashboard() {
const navigate = useNavigate() const navigate = useNavigate()
const stats = useQuery({ queryKey: ["admin_stats"], queryFn: () => api("adminStats", null, "GET") }) const stats = useQuery({ queryKey: ["admin_stats"], queryFn: () => api("adminStats", null, "GET") })
@@ -51,21 +42,6 @@ export default function Dashboard() {
return ( return (
<div className="space-y-5"> <div className="space-y-5">
<Card>
<CardHeader><CardTitle className="text-base">用户注册统计</CardTitle></CardHeader>
<CardContent>
{today.isPending ? <Loading rows={1} /> : today.isError ? <ErrorBox error={today.error} /> : (
<div className="grid grid-cols-2 gap-3 sm:grid-cols-3 lg:grid-cols-5">
<StatCard label="今日新注册" value={today.data.today_registers} tone="pink" />
<StatCard label="本月新注册" value={today.data.month_registers} tone="violet" />
<StatCard label="总用户数" value={today.data.total_users} tone="green" />
<StatCard label="总情侣数" value={today.data.total_couples} tone="blue" />
<StatCard label="所有用户已用存储" value={formatBytes(today.data.total_storage_used)} tone="amber" />
</div>
)}
</CardContent>
</Card>
<div className="dashboard-intro"><div><PageTitle>空间动态</PageTitle><p>用户、关系与生活记录,一览即知。</p></div><Button variant="outline" onClick={() => navigate("/unbind")}>查看解绑请求 <ArrowUpRight size={16}/></Button></div> <div className="dashboard-intro"><div><PageTitle>空间动态</PageTitle><p>用户、关系与生活记录,一览即知。</p></div><Button variant="outline" onClick={() => navigate("/unbind")}>查看解绑请求 <ArrowUpRight size={16}/></Button></div>
{stats.isPending ? <Loading rows={2} /> : stats.isError ? <ErrorBox error={stats.error} /> : ( {stats.isPending ? <Loading rows={2} /> : stats.isError ? <ErrorBox error={stats.error} /> : (
@@ -92,6 +68,20 @@ export default function Dashboard() {
</div> </div>
)} )}
<Card>
<CardHeader><CardTitle className="text-base">用户注册统计</CardTitle></CardHeader>
<CardContent>
{today.isPending ? <Loading rows={1} /> : today.isError ? <ErrorBox error={today.error} /> : (
<div className="grid grid-cols-2 gap-3 md:grid-cols-4">
<StatCard label="今日新注册" value={today.data.today_registers} tone="pink" />
<StatCard label="本月新注册" value={today.data.month_registers} tone="violet" />
<StatCard label="总用户数" value={today.data.total_users} tone="green" />
<StatCard label="总情侣数" value={today.data.total_couples} tone="blue" />
</div>
)}
</CardContent>
</Card>
<Card> <Card>
<CardHeader><CardTitle className="text-base">按日期查询</CardTitle></CardHeader> <CardHeader><CardTitle className="text-base">按日期查询</CardTitle></CardHeader>
<CardContent className="space-y-4"> <CardContent className="space-y-4">
+3 -3
View File
@@ -1,3 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
<path d="M15 18l-6-6 6-6"/> <path d="M15 18l-6-6 6-6"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 201 B

After

Width:  |  Height:  |  Size: 198 B

+4 -4
View File
@@ -1,4 +1,4 @@
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M18 6L6 18" stroke="#FF6B81" stroke-width="2.5" stroke-linecap="round"/> <path d="M18 6L6 18" stroke="#FF6B81" stroke-width="2.5" stroke-linecap="round"/>
<path d="M6 6L18 18" stroke="#FF6B81" stroke-width="2.5" stroke-linecap="round"/> <path d="M6 6L18 18" stroke="#FF6B81" stroke-width="2.5" stroke-linecap="round"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 252 B

After

Width:  |  Height:  |  Size: 248 B

+2 -2
View File
@@ -1,3 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="#999" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="#999" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/> <path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 235 B

After

Width:  |  Height:  |  Size: 233 B

+2 -2
View File
@@ -1,3 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#ff4d4f"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#ff4d4f">
<path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z"/> <path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 176 B

After

Width:  |  Height:  |  Size: 174 B

+2 -2
View File
@@ -1,3 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#666"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#666">
<path d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z"/> <path d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 245 B

After

Width:  |  Height:  |  Size: 243 B

+4 -4
View File
@@ -1,4 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="#FFFFFF" stroke-width="2.8" stroke-linecap="round" stroke-linejoin="round"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="#FFFFFF" stroke-width="2.8" stroke-linecap="round" stroke-linejoin="round">
<line x1="12" y1="6" x2="12" y2="18"/> <line x1="12" y1="6" x2="12" y2="18"/>
<line x1="6" y1="12" x2="18" y2="12"/> <line x1="6" y1="12" x2="18" y2="12"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 249 B

After

Width:  |  Height:  |  Size: 245 B

+9 -1
View File
@@ -12,15 +12,23 @@ Page(withDataCache(withListPagination({
myName: '我', partnerName: 'TA', myName: '我', partnerName: 'TA',
weekBoth: 0, weekMy: 0, weekPartner: 0, weekBoth: 0, weekMy: 0, weekPartner: 0,
todayMy: 0, todayPartner: 0, todayMy: 0, todayPartner: 0,
smokingVisible: true,
loading: true loading: true
}, },
onLoad: function() { onLoad: function() {
this.setData(getLayout()); this.setData(getLayout());
this.refreshSmokingVisible();
this.loadCoupleInfo(); this.loadCoupleInfo();
this.loadData(); this.loadData();
}, },
onShow: function() { this.loadCoupleInfo(); this.loadData(); }, onShow: function() { this.refreshSmokingVisible(); this.loadCoupleInfo(); this.loadData(); },
// 读取本地设置:抽烟打卡默认事件是否显示(默认显示)
refreshSmokingVisible: function() {
var v = wx.getStorageSync('smokingVisible');
this.setData({ smokingVisible: (v === '' || v == null) ? true : !!v });
},
onSmokingUpdated: function() { this.loadData(); }, onSmokingUpdated: function() { this.loadData(); },
+1 -1
View File
@@ -25,7 +25,7 @@
</view> </view>
</view> </view>
<smoking-card id="smoking" bind:updated="onSmokingUpdated" /> <smoking-card id="smoking" wx:if="{{smokingVisible}}" bind:updated="onSmokingUpdated" />
<!-- 打卡列表 --> <!-- 打卡列表 -->
<view class="checkin-cards" wx:if="{{!loading && !loadError && checkins.length > 0}}"> <view class="checkin-cards" wx:if="{{!loading && !loadError && checkins.length > 0}}">
+18 -1
View File
@@ -26,6 +26,9 @@ Page({
subscribeItems: [], subscribeItems: [],
subscribeLoading: false, subscribeLoading: false,
// 打卡:抽烟打卡默认事件是否显示
smokingVisible: true,
// 我们past // 我们past
showAboutModal: false, showAboutModal: false,
// 联系我们 // 联系我们
@@ -33,13 +36,15 @@ Page({
}, },
onLoad: function() { onLoad: function() {
this.setData(getLayout());}, this.setData(getLayout());
this.refreshSmokingVisible();},
onPullDownRefresh: function() { onPullDownRefresh: function() {
wx.stopPullDownRefresh(); wx.stopPullDownRefresh();
}, },
onShow: async function() { onShow: async function() {
this.refreshSmokingVisible();
this.setData({ bindingKnown: false, bindingError:false }); this.setData({ bindingKnown: false, bindingError:false });
try { try {
var info = await api.coupleInfo(); var info = await api.coupleInfo();
@@ -82,6 +87,18 @@ Page({
noop: function() {}, noop: function() {},
// ===== 抽烟打卡默认事件显示开关 =====
refreshSmokingVisible: function() {
var v = wx.getStorageSync('smokingVisible');
this.setData({ smokingVisible: (v === '' || v == null) ? true : !!v });
},
toggleSmoking: function(e) {
var visible = !!e.detail.value;
this.setData({ smokingVisible: visible });
wx.setStorageSync('smokingVisible', visible);
wx.showToast({ title: visible ? '已显示抽烟打卡' : '已隐藏抽烟打卡', icon: 'none' });
},
// ===== 消息通知管理(统一使用一个模板) ===== // ===== 消息通知管理(统一使用一个模板) =====
showSubscribeModal: async function() { showSubscribeModal: async function() {
this.setData({ showSubscribeModal: true, subscribeLoading: true }); this.setData({ showSubscribeModal: true, subscribeLoading: true });
+9
View File
@@ -24,6 +24,15 @@
<text class="j-link">›</text> <text class="j-link">›</text>
</view> </view>
<!-- 抽烟打卡默认事件 -->
<view class="j-profile-setting">
<view class="setting-info">
<view class="j-small-title">抽烟打卡</view>
<view class="j-caption">在打卡页显示「抽烟记录」默认事件</view>
</view>
<switch checked="{{smokingVisible}}" bindchange="toggleSmoking" color="#B74768" style="transform:scale(0.75);" />
</view>
<view class="section-heading">关系与账号</view> <view class="section-heading">关系与账号</view>
<!-- 操作记录 --> <!-- 操作记录 -->
<view class="j-profile-setting" bindtap="goToHistory"> <view class="j-profile-setting" bindtap="goToHistory">
+67 -67
View File
@@ -1,68 +1,68 @@
{ {
"compileType": "miniprogram", "compileType": "miniprogram",
"appid": "wxdc40d0c51cf8fe1e", "appid": "wxdc40d0c51cf8fe1e",
"projectname": "couple-space", "projectname": "couple-space",
"description": "情侣空间小程序", "description": "情侣空间小程序",
"setting": { "setting": {
"urlCheck": false, "urlCheck": false,
"es6": true, "es6": true,
"enhance": true, "enhance": true,
"postcss": true, "postcss": true,
"preloadBackgroundData": false, "preloadBackgroundData": false,
"minified": true, "minified": true,
"newFeature": true, "newFeature": true,
"coverView": true, "coverView": true,
"nodeModules": false, "nodeModules": false,
"autoAudits": false, "autoAudits": false,
"showShadowRootInWxmlPanel": true, "showShadowRootInWxmlPanel": true,
"scopeDataCheck": false, "scopeDataCheck": false,
"uglifyFileName": false, "uglifyFileName": false,
"checkInvalidKey": true, "checkInvalidKey": true,
"checkSiteMap": true, "checkSiteMap": true,
"uploadWithSourceMap": true, "uploadWithSourceMap": true,
"compileHotReLoad": false, "compileHotReLoad": false,
"lazyloadPlaceholderEnable": false, "lazyloadPlaceholderEnable": false,
"useMultiFrameRuntime": true, "useMultiFrameRuntime": true,
"useApiHook": true, "useApiHook": true,
"useApiHostProcess": true, "useApiHostProcess": true,
"babelSetting": { "babelSetting": {
"ignore": [], "ignore": [],
"disablePlugins": [], "disablePlugins": [],
"outputPath": "" "outputPath": ""
}, },
"bundle": false, "bundle": false,
"useIsolateContext": true, "useIsolateContext": true,
"userConfirmedBundleSwitch": false, "userConfirmedBundleSwitch": false,
"packNpmManually": false, "packNpmManually": false,
"packNpmRelationList": [], "packNpmRelationList": [],
"minifyWXSS": true, "minifyWXSS": true,
"compileWorklet": false, "compileWorklet": false,
"minifyWXML": true, "minifyWXML": true,
"localPlugins": false, "localPlugins": false,
"disableUseStrict": false, "disableUseStrict": false,
"useCompilerPlugins": false, "useCompilerPlugins": false,
"condition": false, "condition": false,
"swc": false, "swc": false,
"disableSWC": true "disableSWC": true
}, },
"condition": { "condition": {
"miniprogram": { "miniprogram": {
"list": [] "list": []
} }
}, },
"editorSetting": { "editorSetting": {
"tabIndent": "auto", "tabIndent": "auto",
"tabSize": 2 "tabSize": 2
}, },
"libVersion": "3.16.0", "libVersion": "3.16.0",
"simulatorPluginLibVersion": {}, "simulatorPluginLibVersion": {},
"packOptions": { "packOptions": {
"ignore": [ "ignore": [
{ {
"value": "tests", "value": "tests",
"type": "folder" "type": "folder"
} }
], ],
"include": [] "include": []
} }
} }
+23 -23
View File
@@ -1,24 +1,24 @@
{ {
"libVersion": "3.16.0", "libVersion": "3.16.0",
"projectname": "couple-space", "projectname": "couple-space",
"condition": {}, "condition": {},
"setting": { "setting": {
"urlCheck": false, "urlCheck": false,
"coverView": true, "coverView": true,
"lazyloadPlaceholderEnable": false, "lazyloadPlaceholderEnable": false,
"skylineRenderEnable": false, "skylineRenderEnable": false,
"preloadBackgroundData": false, "preloadBackgroundData": false,
"autoAudits": false, "autoAudits": false,
"useApiHook": true, "useApiHook": true,
"showShadowRootInWxmlPanel": true, "showShadowRootInWxmlPanel": true,
"useStaticServer": false, "useStaticServer": false,
"useLanDebug": false, "useLanDebug": false,
"showES6CompileOption": false, "showES6CompileOption": false,
"compileHotReLoad": true, "compileHotReLoad": true,
"useGlassEaselForWxml": false, "useGlassEaselForWxml": false,
"checkInvalidKey": true, "checkInvalidKey": true,
"ignoreDevUnusedFiles": true, "ignoreDevUnusedFiles": true,
"bigPackageSizeSupport": false, "bigPackageSizeSupport": false,
"useIsolateContext": true "useIsolateContext": true
} }
} }