// 项目资源(Properties.Resources):学生从平台素材库里选图片和声音,平台生成 Properties/Resources.Designer.cs。 // 生成的类和 VS 的强类型资源类用法一样(Properties.Resources.switch_on 是 Bitmap,声音是 byte[]), // 取值时调用运行器的素材库。这个文件由平台生成,不在标签页里显示。 import { ref } from 'vue' import type { SourceFile } from '@iot/shared' export interface GalleryItem { /** 资源名,也是 Properties.Resources 的属性名,和教材一致(如 switch_on) */ name: string file: string /** 中文说明 */ label: string kind: 'image' | 'audio' } export const RESOURCES_FILE = 'Properties/Resources.Designer.cs' /** 素材清单(服务器上 /resources/index.json),第一次用到时加载 */ export const gallery = ref([]) let loading: Promise | undefined export function loadGallery() { loading ??= fetch('/resources/index.json') .then((r) => (r.ok ? r.json() : [])) .then((items: GalleryItem[]) => { gallery.value = items }) .catch(() => { loading = undefined }) return loading } /** 素材文件的网址(设计器预览、资源对话框里显示) */ export function resourceUrl(name: string) { const item = gallery.value.find((g) => g.name === name) return `/resources/${item?.file ?? `${name}.png`}` } /** 工程里已添加的资源名(从生成的 Resources.Designer.cs 里读出) */ export function projectResources(files: SourceFile[]): string[] { const text = files.find((f) => f.path === RESOURCES_FILE)?.content ?? '' return [...text.matchAll(/internal static \S+ ([\p{L}\p{N}_]+) \{/gu)].map((m) => m[1]) } /** 设计器里引用资源的写法:global::命名空间.Properties.Resources.名字 */ export const resourcePrefix = (namespace: string) => `global::${namespace}.Properties.Resources.` /** 从属性值里认出资源名:global::X.Properties.Resources.switch_off → switch_off */ export function resourceNameOf(text: string) { return /\.Properties\.Resources\.([\p{L}\p{N}_]+)$/u.exec(text.trim())?.[1] } /** 生成 Properties/Resources.Designer.cs;没有资源时返回 null(删掉这个文件) */ export function resourcesFile(namespace: string, names: string[]): SourceFile | null { const items = names.map((name) => gallery.value.find((g) => g.name === name)).filter((g): g is GalleryItem => g !== undefined) if (items.length === 0) return null const members = items.map((item) => item.kind === 'image' ? ` /// ${item.label}\n internal static System.Drawing.Bitmap ${item.name} {\n get { return global::Sim.Host.ProjectResources.Image("${item.file}"); }\n }` : ` /// ${item.label}\n internal static byte[] ${item.name} {\n get { return global::Sim.Host.ProjectResources.Bytes("${item.file}"); }\n }`, ) const content = `//------------------------------------------------------------------------------ // // 项目资源(平台素材库)。在"项目资源"里添加或移除,不要手动修改这个文件。 // //------------------------------------------------------------------------------ namespace ${namespace}.Properties { /// /// 项目资源:Properties.Resources.资源名 /// internal class Resources { ${members.join('\n\n')} } } ` return { path: RESOURCES_FILE, content } }