diff --git a/miniprogram/app.json b/miniprogram/app.json index ce9b63f..96b81db 100644 --- a/miniprogram/app.json +++ b/miniprogram/app.json @@ -14,7 +14,6 @@ "guide/guide", "settings/settings", "debug/debug", - "worksheetSync/worksheetSync", "categoryManage/categoryManage", "categoryContentManage/categoryContentManage", "homeContentManage/homeContentManage", @@ -42,6 +41,12 @@ "name": "focusPages", "pages": ["focusDraw/focusDraw", "shape/shape"], "independent": false + }, + { + "root": "chinesePages", + "name": "chinesePages", + "pages": ["wordColoring/wordColoring"], + "independent": false } ], "preloadRule": { diff --git a/miniprogram/chinesePages/wordColoring/wordColoring.config.ts b/miniprogram/chinesePages/wordColoring/wordColoring.config.ts new file mode 100644 index 0000000..6224d76 --- /dev/null +++ b/miniprogram/chinesePages/wordColoring/wordColoring.config.ts @@ -0,0 +1,95 @@ +import type { DebugPublishMeta } from '../../utils/debugPublish'; +import { inferGradeFromAge } from '../../utils/debugPublish'; +import type { TemplateType } from '../../service/drawServiceFactory'; + +/** 本地 worksheet 元数据(与云库 `worksheets` 文档 `_id` 对齐) */ +interface WordColoringWorksheetDefinition { + id: string; + templateType: TemplateType; + icon: string; + title: string; + subtitle: string; + ageMin: number; + ageMax: number; + difficulty: 1 | 2 | 3 | 4; + tags: string[]; + sortOrder: number; +} + +export const WORD_COLORING_WORKSHEET_DEFINITIONS = [ + { + id: 'word-coloring-grid', + templateType: 'grid' as TemplateType, + icon: 'grid', + title: '网格涂色', + subtitle: '田字格涂色识字练习', + ageMin: 3, + ageMax: 6, + difficulty: 1, + tags: ['识字', '涂色', '田字格'], + sortOrder: 30, + }, + { + id: 'word-coloring-find', + templateType: 'find' as TemplateType, + icon: 'search', + title: '找字涂色', + subtitle: '在字海中找到目标字并涂色', + ageMin: 4, + ageMax: 7, + difficulty: 2, + tags: ['识字', '涂色', '找字'], + sortOrder: 31, + }, +] as const satisfies ReadonlyArray; + +type WordColoringWorksheetRow = + (typeof WORD_COLORING_WORKSHEET_DEFINITIONS)[number]; + +const WORD_COLORING_WORKSHEET_BY_ID = Object.fromEntries( + WORD_COLORING_WORKSHEET_DEFINITIONS.map((m) => [m.id, m]), +) as Record; + +/** 页面渲染用:模式选择器列表 */ +export const WORD_COLORING_MODE_OPTIONS = WORD_COLORING_WORKSHEET_DEFINITIONS; + +/** 页面 pageInfoLookup 用 */ +export function getModeInfo(id: string) { + const m = WORD_COLORING_WORKSHEET_BY_ID[id]; + return m ? { title: m.title, desc: m.subtitle } : undefined; +} + +/** 判断 id 是否有效 */ +export function isValidMode(id: string): boolean { + return id in WORD_COLORING_WORKSHEET_BY_ID; +} + +/** 根据 id 获取 templateType */ +export function getTemplateType(id: string): TemplateType { + const m = WORD_COLORING_WORKSHEET_BY_ID[id]; + return m?.templateType || 'grid'; +} + +/** 发布用:从当前 mode 生成 DebugPublishMeta */ +export function getPublishMetaByMode(id: string): DebugPublishMeta | null { + const m = WORD_COLORING_WORKSHEET_BY_ID[id]; + if (!m) return null; + return { + id: m.id, + title: m.title, + subtitle: m.subtitle, + category: 'chinese', + subcategory: 'word-coloring', + path: `/chinesePages/wordColoring/wordColoring?id=${m.id}`, + ageMin: m.ageMin, + ageMax: m.ageMax, + grade: inferGradeFromAge(m.ageMin, m.ageMax), + difficulty: m.difficulty, + previewImg: '', + tags: [...m.tags], + isNew: false, + isHot: false, + sortOrder: m.sortOrder, + status: 'draft', + }; +} diff --git a/miniprogram/chinesePages/wordColoring/wordColoring.json b/miniprogram/chinesePages/wordColoring/wordColoring.json new file mode 100644 index 0000000..1eb093c --- /dev/null +++ b/miniprogram/chinesePages/wordColoring/wordColoring.json @@ -0,0 +1,23 @@ +{ + "navigationStyle": "custom", + "navigationBarTitleText": "涂色识字", + "navigationBarBackgroundColor": "#F8F0E0", + "navigationBarTextStyle": "black", + "backgroundColor": "#FEF6E7", + "enablePullDownRefresh": false, + "usingComponents": { + "nav-bar": "../../components3.0/nav-bar/nav-bar", + "preview-card": "../../components3.0/preview-card/preview-card", + "preview-footer-actions": "../../components3.0/preview-footer-actions/preview-footer-actions", + "debug-publish-tools": "../../components3.0/debug-publish-tools/debug-publish-tools", + "share-guide-popup": "../../components/share-guide-popup/share-guide-popup", + "draw-ad": "../../components/draw-ad/draw-ad", + "toy-icon": "../../toy/icon/icon", + "toy-button": "../../toy/button-v2/button", + "word-input": "../../components/word-input/word-input", + "word-card": "../../components/word-card/word-card", + "color-picker": "../../components/color-picker/color-picker", + "word-picker": "../../components/word-picker/word-picker", + "empty-state": "../../components/empty-state/empty-state" + } +} diff --git a/miniprogram/chinesePages/wordColoring/wordColoring.less b/miniprogram/chinesePages/wordColoring/wordColoring.less new file mode 100644 index 0000000..91ce64a --- /dev/null +++ b/miniprogram/chinesePages/wordColoring/wordColoring.less @@ -0,0 +1,108 @@ +@import '../../style/theme.less'; + +.wc-page { + min-height: 100vh; + background: @bg-page; + box-sizing: border-box; +} + +.wc-main { + padding: @page-padding-x; + padding-bottom: calc(120rpx + env(safe-area-inset-bottom)); +} + +.wc-section { + margin-top: @section-gap-sm; +} + +.wc-section-title { + display: block; + font-size: 26rpx; + font-weight: 700; + color: @text-secondary; + letter-spacing: 0.04em; + margin-bottom: 20rpx; +} + +/* 输入行 */ +.wc-input-row { + display: flex; + flex-direction: row; + align-items: center; + gap: 16rpx; +} + +/* 文字卡片网格 */ +.wc-card-grid { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 24rpx; +} + +/* 操作按钮行 */ +.wc-action-row { + display: flex; + flex-direction: row; + align-items: center; + gap: 16rpx; +} + +/* 空状态 */ +.wc-empty { + padding: 48rpx 0; +} + +/* 模板选择网格(2列) */ +.wc-mode-grid { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 20rpx; +} + +.wc-mode-card { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 12rpx; + padding: 32rpx 16rpx; + border-radius: @radius-lg; + background: @bg-header; + box-shadow: @shadow; + transition: transform 0.12s, box-shadow 0.12s; +} + +.wc-mode-card--active { + background: @brand; + box-shadow: @shadow, 0 0 0 4rpx fade(@brand, 30%); +} + +.wc-mode-card--pressed { + transform: scale(0.96); +} + +.wc-mode-card__icon { + margin-bottom: 4rpx; +} + +.wc-mode-card__label { + font-size: 26rpx; + font-weight: 700; + color: @text-title; + line-height: 1.3; +} + +.wc-mode-card--active .wc-mode-card__label { + color: @text-selected-btn; +} + +.wc-mode-card__sub { + font-size: 20rpx; + color: @text-secondary; + text-align: center; + line-height: 1.3; +} + +.wc-mode-card--active .wc-mode-card__sub { + color: fade(@text-selected-btn, 75%); +} diff --git a/miniprogram/chinesePages/wordColoring/wordColoring.ts b/miniprogram/chinesePages/wordColoring/wordColoring.ts new file mode 100644 index 0000000..6058262 --- /dev/null +++ b/miniprogram/chinesePages/wordColoring/wordColoring.ts @@ -0,0 +1,312 @@ +import { WATER_COLORS } from '../../constants/colors'; +import { WORDS } from '../../constants/words'; +import { DrawServiceFactory, type IDrawService } from '../../service/drawServiceFactory'; +import { createPage, type CanvasDataState } from '../../base/pageMixin'; +import { defaultShareConfig } from '../../config/config'; +import { + getModeInfo, + getPublishMetaByMode, + getTemplateType, + isValidMode, + WORD_COLORING_MODE_OPTIONS, + WORD_COLORING_WORKSHEET_DEFINITIONS, +} from './wordColoring.config'; +import type { DebugPublishMeta } from '../../utils/debugPublish'; +import { addFavorite, removeFavorite, batchCheckFavorited } from '../../utils/favorites'; + +type CardItem = { color: string; word: string }; + +const COLOR_MAP: Record = { + 红: '#FF0000', 蓝: '#0000FF', 绿: '#00FF00', 黄: '#FFFF00', + 黑: '#000000', 白: '#FFFFFF', 紫: '#800080', 橙: '#FF7F00', + 粉: '#FF69B4', 棕: '#A52A2A', 灰: '#808080', +}; + +const pageInfoLookup = getModeInfo; + +// PLACEHOLDER_TS_PART2 + +type PageData = CanvasDataState & { + worksheetId: string; + cardList: CardItem[]; + selectedWords: string[]; + showColorPopup: boolean; + currentKey: number; + currentColor: string; + showSelectWordPopup: boolean; + modeOptions: typeof WORD_COLORING_MODE_OPTIONS; + isPreviewFavorite: boolean; + isDevEnv: boolean; + debugPublishVisible: boolean; + debugPublishLoading: boolean; + debugPublishMeta: DebugPublishMeta | null; +}; + +createPage( + { + canvas: null as Canvas | null, + ctx: null as RenderingContext | null, + boxHeight: 0, + boxWidth: 0, + drawService: null as IDrawService | null, + _favoritedMap: {} as Record, + + data: { + pageTitle: '涂色识字', + functionId: '', + hasContent: false, + showShareDialog: false, + worksheetId: 'word-coloring-grid', + cardList: [] as CardItem[], + selectedWords: [] as string[], + showColorPopup: false, + currentKey: 0, + currentColor: '', + showSelectWordPopup: false, + modeOptions: WORD_COLORING_MODE_OPTIONS, + isPreviewFavorite: false, + isDevEnv: false, + debugPublishVisible: false, + debugPublishLoading: false, + debugPublishMeta: null, + } as unknown as PageData, + + onLoad(options: { id?: string }) { + const worksheetId = + options.id && isValidMode(options.id) + ? options.id + : 'word-coloring-grid'; + + this.syncDebugPublishEnv(); + this.setData({ + worksheetId, + functionId: worksheetId, + }); + this.initPageInfo(worksheetId, '涂色识字'); + this.loadFavoritedMap(); + }, + + onCanvasReady(e: WechatMiniprogram.CustomEvent) { + const worksheetId = this.data.worksheetId; + const templateType = getTemplateType(worksheetId); + + this.initCanvasFromComponent(e.detail, { + createDrawService: ( + canvas: Canvas, + ctx: RenderingContext, + options?: Record, + ) => DrawServiceFactory.create(templateType, canvas, ctx, options), + drawServiceOptions: { + title: this.data.pageTitle, + }, + onCanvasReady: () => { + if (this.data.cardList.length > 0) { + this.drawCanvas(); + } + }, + }); + }, + +// PLACEHOLDER_TS_PART3 + + /** 执行 Canvas 绘制 */ + async drawCanvas() { + if (!this.drawService) return; + const cardList = this.data.cardList; + if (cardList.length === 0) { + this.setData({ hasContent: false }); + return; + } + try { + await this.drawService.draw(cardList); + this.setData({ hasContent: true }); + } catch (e) { + console.error('绘制失败:', e); + this.setData({ hasContent: false }); + } + }, + + /** 切换模板类型 */ + onSelectMode(e: WechatMiniprogram.TouchEvent) { + const id = e.currentTarget.dataset.id as string; + if (!id || id === this.data.worksheetId || !isValidMode(id)) return; + + const templateType = getTemplateType(id); + this.setData({ + worksheetId: id, + functionId: id, + isPreviewFavorite: !!this._favoritedMap[id], + }); + this.initPageInfo(id, '涂色识字'); + + if (this.canvas && this.ctx) { + this.drawService = DrawServiceFactory.create( + templateType, + this.canvas, + this.ctx, + { title: this.data.pageTitle }, + ); + if (this.data.cardList.length > 0) { + this.drawCanvas(); + } + } + }, + + /** preview-card 换一批 */ + onPreviewRefresh() { + this.refreshCardList(); + }, + + /** 随机生成文字卡片 */ + refreshCardList() { + const allWords = WORDS.slice(0, 2).reduce( + (acc, cat) => acc.concat(cat.words), + [] as string[], + ); + const selected: string[] = []; + while (selected.length < 6 && allWords.length > 0) { + const idx = Math.floor(Math.random() * allWords.length); + const w = allWords[idx]; + if (!selected.includes(w)) selected.push(w); + } + const colors = [...WATER_COLORS.basic12].sort(() => Math.random() - 0.5); + const cardList = selected.map((word, i) => ({ + word, + color: COLOR_MAP[word] || colors[i % colors.length].hex, + })); + this.setData({ cardList, selectedWords: selected }, () => { + this.drawCanvas(); + }); + }, + + /** 清空文字卡片 */ + clearCardList() { + this.setData({ cardList: [], selectedWords: [], hasContent: false }); + }, + +// PLACEHOLDER_TS_PART4 + + /** 输入确认:添加文字卡片 */ + onConfirmInput(e: WechatMiniprogram.Input) { + const { cardList } = this.data; + const { value } = e.detail; + const characters = value.split(''); + const remainingSlots = 6 - cardList.length; + if (remainingSlots <= 0) { + wx.showToast({ title: '最多只能添加6个字哦', icon: 'none' }); + return; + } + + const usedColors = cardList.map((item) => item.color); + const usedWords = cardList.map((item) => item.word); + const allColors = WATER_COLORS.basic12.map((c) => c.hex); + const available = allColors.filter((c) => !usedColors.includes(c)); + const shuffled = [...available].sort(() => Math.random() - 0.5); + + const newChars: string[] = []; + for (const char of characters) { + if (newChars.length >= remainingSlots) break; + if (!usedWords.includes(char) && !newChars.includes(char)) { + newChars.push(char); + } + } + + const newCards = newChars.map((char, i) => { + const mapped = COLOR_MAP[char]; + const color = + mapped && !usedColors.includes(mapped) + ? mapped + : shuffled[i % shuffled.length]; + return { word: char, color }; + }); + + const updated = [...cardList, ...newCards]; + this.setData( + { cardList: updated, selectedWords: updated.map((c) => c.word) }, + () => this.drawCanvas(), + ); + }, + + /** 删除单个文字卡片 */ + deleteWordCard(e: WechatMiniprogram.CustomEvent) { + const { key } = e.detail; + const updated = this.data.cardList.filter((_, i) => i !== key); + this.setData( + { cardList: updated, selectedWords: updated.map((c) => c.word) }, + () => this.drawCanvas(), + ); + }, + + /** 颜色选择相关 */ + onColorTap(e: WechatMiniprogram.CustomEvent) { + const { key, color } = e.detail; + this.setData({ showColorPopup: true, currentKey: key, currentColor: color }); + }, + + onCloseColorPopup() { + this.setData({ showColorPopup: false, currentKey: 0, currentColor: '' }); + }, + + onChangeColor(e: WechatMiniprogram.CustomEvent) { + const { color } = e.detail; + const { currentKey, cardList } = this.data; + const updated = [...cardList]; + updated[currentKey] = { ...updated[currentKey], color }; + this.setData({ showColorPopup: false, cardList: updated }, () => { + this.drawCanvas(); + }); + }, + + /** 文字选择弹窗 */ + openSelectWordPopup() { + this.setData({ showSelectWordPopup: true }); + }, + + closeSelectWordPopup() { + this.setData({ showSelectWordPopup: false }); + }, + + onChangeWord(e: WechatMiniprogram.CustomEvent) { + const selectedWords = e.detail.selectedWords as string[]; + const colors = [...WATER_COLORS.basic12]; + const cardList = selectedWords.map((word, i) => ({ + word, + color: COLOR_MAP[word] || colors[i % colors.length].hex, + })); + this.setData({ showSelectWordPopup: false, cardList, selectedWords }, () => { + this.drawCanvas(); + }); + }, + + /** 收藏 */ + async onPreviewFavorite() { + const next = !this.data.isPreviewFavorite; + this.setData({ isPreviewFavorite: next }); + const id = this.data.worksheetId; + if (id) { + this._favoritedMap[id] = next; + if (next) addFavorite(id); + else removeFavorite(id); + } + wx.showToast({ title: next ? '收藏成功' : '已取消收藏', icon: 'none' }); + }, + + async loadFavoritedMap() { + const ids = WORD_COLORING_WORKSHEET_DEFINITIONS.map((d) => d.id); + this._favoritedMap = await batchCheckFavorited(ids); + if (this._favoritedMap[this.data.worksheetId]) { + this.setData({ isPreviewFavorite: true }); + } + }, + + getPublishMeta(): DebugPublishMeta { + const meta = getPublishMetaByMode(this.data.worksheetId); + if (!meta) throw new Error('当前题型配置不存在'); + return meta; + }, + }, + { + shareConfig: defaultShareConfig, + pageInfoLookup, + }, +); diff --git a/miniprogram/chinesePages/wordColoring/wordColoring.wxml b/miniprogram/chinesePages/wordColoring/wordColoring.wxml new file mode 100644 index 0000000..a94c8c5 --- /dev/null +++ b/miniprogram/chinesePages/wordColoring/wordColoring.wxml @@ -0,0 +1,130 @@ + + + + + + + + + 添加文字 + + + + 选择文字 + + + + + + + + + + + + + + + + + + + 随机生成 + + + 清空 + + + + + + + 选择模板 + + + + {{item.title}} + {{item.subtitle}} + + + + + + + + + + + + + + + + + diff --git a/miniprogram/pages/category/category.less b/miniprogram/pages/category/category.less index ae952ef..474f38c 100644 --- a/miniprogram/pages/category/category.less +++ b/miniprogram/pages/category/category.less @@ -70,9 +70,10 @@ .cat-sidebar__item { display: flex; - flex-direction: column; + flex-direction: row; align-items: center; - gap: 6rpx; + justify-content: center; + gap: 8rpx; padding: 24rpx 12rpx; margin: 4rpx 12rpx; border-radius: 999rpx; @@ -86,7 +87,7 @@ } .cat-sidebar__icon { - font-size: 36rpx; + font-size: 32rpx; line-height: 1; } @@ -263,35 +264,47 @@ color: @text-gray; } -// ── Skeleton ── -@keyframes skeleton-pulse { - 0% { - opacity: 0.6; - } +// ── Skeleton shimmer ── +@skeleton-base: #e8e2d5; - 50% { - opacity: 0.3; +@keyframes skeleton-shimmer { + 0% { + transform: translateX(-100%); } 100% { - opacity: 0.6; + transform: translateX(100%); } } .cat-card--skeleton { pointer-events: none; + position: relative; + + &::after { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: linear-gradient(135deg, + transparent 25%, + rgba(255, 255, 255, 0.7) 50%, + transparent 75%); + animation: skeleton-shimmer 1.2s linear infinite; + z-index: 1; + } .cat-card__thumb { - background: #e8e2d5; - animation: skeleton-pulse 1.5s ease-in-out infinite; + background: @skeleton-base; } .cat-card__title, .cat-card__subtitle { - background: #e8e2d5; + background: @skeleton-base; border-radius: 8rpx; color: transparent; - animation: skeleton-pulse 1.5s ease-in-out infinite; } .cat-card__title { diff --git a/miniprogram/pages/category/category.ts b/miniprogram/pages/category/category.ts index cc34f61..cc2ea9f 100644 --- a/miniprogram/pages/category/category.ts +++ b/miniprogram/pages/category/category.ts @@ -24,13 +24,18 @@ const DIFFICULTY_LABELS: Record = { 4: '挑战', }; -const SIDEBAR_TABS: CategoryTab[] = CATEGORY_LIST_WITH_ALL.map( - ({ id, name, icon }) => ({ - id, - name, - icon, - }), -); +const DYNAMIC_TABS: CategoryTab[] = [ + { id: 'hot', name: '热门推荐', icon: '🔥' }, + { id: 'top-downloads', name: '下载最多', icon: '📥' }, +]; + +const SIDEBAR_TABS: CategoryTab[] = [ + { id: 'all', name: '全部', icon: '📋' }, + ...DYNAMIC_TABS, + ...CATEGORY_LIST_WITH_ALL.filter((c) => c.id !== 'all').map( + ({ id, name, icon }) => ({ id, name, icon }), + ), +]; const TAB_BAR_PATHS = new Set([ '/pages/home/home', @@ -119,9 +124,23 @@ function buildAllItems(): CategoryItem[] { return sortWorksheets(items); } +const DYNAMIC_LIMIT = 12; + +function buildHotItems(): CategoryItem[] { + const all = buildAllItems(); + return [...all].sort((a, b) => (b.likes || 0) - (a.likes || 0)).slice(0, DYNAMIC_LIMIT); +} + +function buildTopDownloadsItems(): CategoryItem[] { + const all = buildAllItems(); + return [...all].sort((a, b) => (b.downloads || 0) - (a.downloads || 0)).slice(0, DYNAMIC_LIMIT); +} + function getItemsByCategory(categoryId: string): CategoryItem[] { if (!_categoryData) return []; if (categoryId === 'all') return buildAllItems(); + if (categoryId === 'hot') return buildHotItems(); + if (categoryId === 'top-downloads') return buildTopDownloadsItems(); const group = _categoryData.categories.find((c) => c.id === categoryId); if (!group) return []; return group.items.map((item) => ({ ...item })); diff --git a/miniprogram/pages/category/category.wxml b/miniprogram/pages/category/category.wxml index e31fdac..2964138 100644 --- a/miniprogram/pages/category/category.wxml +++ b/miniprogram/pages/category/category.wxml @@ -37,7 +37,9 @@ class="cat-sidebar__item {{activeCategoryId === item.id ? 'cat-sidebar__item--active' : ''}}" data-id="{{item.id}}" bindtap="onTapCategory"> - + {{item.icon}} {{item.name}} diff --git a/miniprogram/pages/profile/profile.ts b/miniprogram/pages/profile/profile.ts index a9abe6c..d419177 100644 --- a/miniprogram/pages/profile/profile.ts +++ b/miniprogram/pages/profile/profile.ts @@ -12,6 +12,7 @@ Page({ data: { userName: '微信用户', avatarUrl: '', + isDevEnv: false, printCount: 0, favoriteCount: 0, version: '3.0.0', @@ -23,6 +24,11 @@ Page({ onLoad() { this.syncUserInfoFromApp(); + const isDevEnv = + wx.getAccountInfoSync().miniProgram.envVersion !== 'release'; + this.setData({ + isDevEnv, + }); }, onShow() { diff --git a/project.config.json b/project.config.json index 92a82f9..50e3c52 100644 --- a/project.config.json +++ b/project.config.json @@ -4,10 +4,7 @@ "compileType": "miniprogram", "cloudfunctionRoot": "cloudfunctions/", "setting": { - "useCompilerPlugins": [ - "typescript", - "less" - ], + "useCompilerPlugins": ["typescript", "less"], "babelSetting": { "ignore": [], "disablePlugins": [], @@ -67,4 +64,4 @@ "cloudfunctionTemplateRoot": "cloudfunctionTemplate/", "appid": "wx4353d20418f2fa37", "projectname": "doodle-mini" -} \ No newline at end of file +} diff --git a/project.private.config.json b/project.private.config.json index 9a98dc0..d48f28b 100644 --- a/project.private.config.json +++ b/project.private.config.json @@ -24,12 +24,19 @@ "miniprogram": { "list": [ { - "name": "pages/profile/profile", - "pathName": "pages/profile/profile", + "name": "chinesePages/wordColoring/wordColoring", + "pathName": "chinesePages/wordColoring/wordColoring", "query": "", "scene": null, "launchMode": "default" }, + { + "name": "pages/profile/profile", + "pathName": "pages/profile/profile", + "query": "", + "launchMode": "default", + "scene": null + }, { "name": "supportPages/index/index", "pathName": "supportPages/index/index",