add text box
5
bun.lock
@ -6,6 +6,7 @@
|
||||
"dependencies": {
|
||||
"openai": "^5.20.0",
|
||||
"vue": "^3.5.18",
|
||||
"vue-router": "4",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^6.0.1",
|
||||
@ -143,6 +144,8 @@
|
||||
|
||||
"@vue/compiler-vue2": ["@vue/compiler-vue2@2.7.16", "", { "dependencies": { "de-indent": "^1.0.2", "he": "^1.2.0" } }, "sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A=="],
|
||||
|
||||
"@vue/devtools-api": ["@vue/devtools-api@6.6.4", "", {}, "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g=="],
|
||||
|
||||
"@vue/language-core": ["@vue/language-core@3.0.6", "", { "dependencies": { "@volar/language-core": "2.4.23", "@vue/compiler-dom": "^3.5.0", "@vue/compiler-vue2": "^2.7.16", "@vue/shared": "^3.5.0", "alien-signals": "^2.0.5", "muggle-string": "^0.4.1", "path-browserify": "^1.0.1", "picomatch": "^4.0.2" }, "peerDependencies": { "typescript": "*" }, "optionalPeers": ["typescript"] }, "sha512-e2RRzYWm+qGm8apUHW1wA5RQxzNhkqbbKdbKhiDUcmMrNAZGyM8aTiL3UrTqkaFI5s7wJRGGrp4u3jgusuBp2A=="],
|
||||
|
||||
"@vue/reactivity": ["@vue/reactivity@3.5.21", "", { "dependencies": { "@vue/shared": "3.5.21" } }, "sha512-3ah7sa+Cwr9iiYEERt9JfZKPw4A2UlbY8RbbnH2mGCE8NwHkhmlZt2VsH0oDA3P08X3jJd29ohBDtX+TbD9AsA=="],
|
||||
@ -205,6 +208,8 @@
|
||||
|
||||
"vue": ["vue@3.5.21", "", { "dependencies": { "@vue/compiler-dom": "3.5.21", "@vue/compiler-sfc": "3.5.21", "@vue/runtime-dom": "3.5.21", "@vue/server-renderer": "3.5.21", "@vue/shared": "3.5.21" }, "peerDependencies": { "typescript": "*" }, "optionalPeers": ["typescript"] }, "sha512-xxf9rum9KtOdwdRkiApWL+9hZEMWE90FHh8yS1+KJAiWYh+iGWV1FquPjoO9VUHQ+VIhsCXNNyZ5Sf4++RVZBA=="],
|
||||
|
||||
"vue-router": ["vue-router@4.5.1", "", { "dependencies": { "@vue/devtools-api": "^6.6.4" }, "peerDependencies": { "vue": "^3.2.0" } }, "sha512-ogAF3P97NPm8fJsE4by9dwSYtDwXIY1nFY9T6DyQnGHd1E2Da94w9JIolpe42LJGIl0DwOHBi8TcRPlPGwbTtw=="],
|
||||
|
||||
"vue-tsc": ["vue-tsc@3.0.6", "", { "dependencies": { "@volar/typescript": "2.4.23", "@vue/language-core": "3.0.6" }, "peerDependencies": { "typescript": ">=5.0.0" }, "bin": { "vue-tsc": "./bin/vue-tsc.js" } }, "sha512-Tbs8Whd43R2e2nxez4WXPvvdjGbW24rOSgRhLOHXzWiT4pcP4G7KeWh0YCn18rF4bVwv7tggLLZ6MJnO6jXPBg=="],
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,7 +10,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"openai": "^5.20.0",
|
||||
"vue": "^3.5.18"
|
||||
"vue": "^3.5.18",
|
||||
"vue-router": "4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^6.0.1",
|
||||
|
||||
1561
src/App.vue
|
Before Width: | Height: | Size: 352 KiB |
16
src/main.ts
@ -1,5 +1,19 @@
|
||||
import { createApp } from 'vue'
|
||||
import App from './App.vue'
|
||||
import './style.css'
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
|
||||
createApp(App).mount('#app')
|
||||
const router = createRouter({
|
||||
history: createWebHistory(),
|
||||
routes: [
|
||||
{
|
||||
path: '/',
|
||||
component: () => import('./views/Home.vue')
|
||||
}, {
|
||||
path: '/lab',
|
||||
component: () => import('./views/VirtualLab.vue')
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
createApp(App).use(router).mount('#app')
|
||||
|
||||
3
src/views/Home.vue
Normal file
@ -0,0 +1,3 @@
|
||||
<template>
|
||||
<div>Home</div>
|
||||
</template>
|
||||
1727
src/views/VirtualLab.vue
Normal file
|
Before Width: | Height: | Size: 234 KiB After Width: | Height: | Size: 234 KiB |
|
Before Width: | Height: | Size: 154 KiB After Width: | Height: | Size: 154 KiB |
|
Before Width: | Height: | Size: 120 KiB After Width: | Height: | Size: 120 KiB |
|
Before Width: | Height: | Size: 245 KiB After Width: | Height: | Size: 245 KiB |
|
Before Width: | Height: | Size: 832 KiB After Width: | Height: | Size: 832 KiB |
|
Before Width: | Height: | Size: 252 KiB After Width: | Height: | Size: 252 KiB |
|
Before Width: | Height: | Size: 405 KiB After Width: | Height: | Size: 405 KiB |
|
Before Width: | Height: | Size: 597 KiB After Width: | Height: | Size: 597 KiB |
BIN
src/views/circuit-ele/resistor.png
Normal file
|
After Width: | Height: | Size: 318 KiB |
|
Before Width: | Height: | Size: 254 KiB After Width: | Height: | Size: 254 KiB |
|
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 37 KiB |
|
Before Width: | Height: | Size: 395 KiB After Width: | Height: | Size: 395 KiB |
|
Before Width: | Height: | Size: 402 KiB After Width: | Height: | Size: 402 KiB |
10
src/views/circuit-ele/text_box.svg
Normal file
@ -0,0 +1,10 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 128 128">
|
||||
<defs>
|
||||
<linearGradient id="bg" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0" stop-color="#ffffff"/>
|
||||
<stop offset="1" stop-color="#f3f4f6"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<rect x="14" y="14" width="100" height="100" rx="12" ry="12" fill="url(#bg)" stroke="#111827" stroke-width="4"/>
|
||||
<text x="50%" y="54%" dominant-baseline="middle" text-anchor="middle" font-family="Arial, Helvetica, sans-serif" font-size="72" fill="#111827">T</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 554 B |
@ -13,6 +13,7 @@ import switchOn from './circuit-ele/switch_on.png'
|
||||
import meter from './circuit-ele/meter.png'
|
||||
import slidingRheostat from './circuit-ele/sliding_rheostat.png'
|
||||
import slidingRheostatPin from './circuit-ele/sliding_rheostat_pin.png'
|
||||
import textBox from './circuit-ele/text_box.svg'
|
||||
|
||||
export type ConnectionPoint = {
|
||||
// 以百分比(0..1)定义在图片盒子内的位置
|
||||
@ -49,6 +50,12 @@ export type PropertySchema =
|
||||
type: 'text'
|
||||
default: string
|
||||
}
|
||||
| {
|
||||
key: string
|
||||
label: string
|
||||
type: 'color'
|
||||
default: string
|
||||
}
|
||||
| {
|
||||
key: string
|
||||
label: string
|
||||
@ -64,14 +71,28 @@ export type Preset = {
|
||||
}
|
||||
|
||||
export const elements: CircuitElement[] = [
|
||||
{
|
||||
key: 'text_box',
|
||||
name: '文本框',
|
||||
url: textBox,
|
||||
defaultSize: 0,
|
||||
// 文本框不参与电路连接,无端点
|
||||
connectionPoints: [],
|
||||
propertySchemas: [
|
||||
{ key: 'text', label: '文本', type: 'text', default: '双击编辑' },
|
||||
{ key: 'fontSize', label: '字体大小', type: 'number', unit: 'px', default: 24 },
|
||||
{ key: 'color', label: '颜色', type: 'color', default: '#111827' },
|
||||
// 可选:是否粗体/对齐方式等,后续再加
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'battery',
|
||||
name: '电池',
|
||||
url: battery,
|
||||
defaultSize: 110,
|
||||
connectionPoints: [
|
||||
{ x: 0.05, y: 0.5, name: 'A' }, // 左侧
|
||||
{ x: 0.95, y: 0.5, name: 'B' }, // 右侧
|
||||
{ x: 0.95, y: 0.5, name: '正极' }, // 右侧
|
||||
{ x: 0.05, y: 0.5, name: '负极' }, // 左侧
|
||||
],
|
||||
propertySchemas: [
|
||||
{ key: 'voltage', label: '电压', type: 'number', unit: 'V', default: 3 },
|
||||
@ -84,8 +105,8 @@ export const elements: CircuitElement[] = [
|
||||
url: powerSupply,
|
||||
defaultSize: 180,
|
||||
connectionPoints: [
|
||||
{ x: 0.2, y: 1, name: 'A' },
|
||||
{ x: 0.8, y: 1, name: 'B' },
|
||||
{ x: 0.8, y: 1, name: '正极' },
|
||||
{ x: 0.2, y: 1, name: '负极' },
|
||||
],
|
||||
propertySchemas: [
|
||||
{ key: 'voltage', label: '电压', type: 'number', unit: 'V', default: 5 },
|
||||
@ -122,32 +143,6 @@ export const elements: CircuitElement[] = [
|
||||
// 当电流超过阈值时在前端根据 state 切换图片
|
||||
stateImages: { on: lightBulbGrow, off: lightBulb },
|
||||
},
|
||||
{
|
||||
key: 'capacitor',
|
||||
name: '电容',
|
||||
url: capacitor,
|
||||
defaultSize: 120,
|
||||
connectionPoints: [
|
||||
{ x: 0.6, y: 0.96, name: 'A' },
|
||||
{ x: 0.4, y: 0.9, name: 'B' },
|
||||
],
|
||||
propertySchemas: [
|
||||
{ key: 'capacitance', label: '电容', type: 'number', unit: 'F', default: 0.000001 },
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'inductor',
|
||||
name: '电感',
|
||||
url: inductor,
|
||||
defaultSize: 100,
|
||||
connectionPoints: [
|
||||
{ x: 0.05, y: 0.5, name: 'A' },
|
||||
{ x: 0.95, y: 0.5, name: 'B' },
|
||||
],
|
||||
propertySchemas: [
|
||||
{ key: 'inductance', label: '电感', type: 'number', unit: 'H', default: 0.001 },
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'sliding_rheostat',
|
||||
name: '滑动变阻器',
|
||||
@ -155,10 +150,10 @@ export const elements: CircuitElement[] = [
|
||||
pinUrl: slidingRheostatPin,
|
||||
defaultSize: 180,
|
||||
connectionPoints: [
|
||||
{ x: 0.15, y: 0.28, name: 'A' },
|
||||
{ x: 0.85, y: 0.28, name: 'B' },
|
||||
{ x: 0.15, y: 0.76, name: 'C' },
|
||||
{ x: 0.85, y: 0.76, name: 'D' },
|
||||
{ x: 0.15, y: 0.28, name: '下部左侧' },
|
||||
{ x: 0.85, y: 0.28, name: '下部右侧' },
|
||||
{ x: 0.15, y: 0.76, name: '上部左侧' },
|
||||
{ x: 0.85, y: 0.76, name: '上部右侧' },
|
||||
],
|
||||
propertySchemas: [
|
||||
{ key: 'maxResistance', label: '最大电阻', type: 'number', unit: 'Ω', default: 100 },
|
||||
@ -197,8 +192,8 @@ export const elements: CircuitElement[] = [
|
||||
url: meter,
|
||||
defaultSize: 150,
|
||||
connectionPoints: [
|
||||
{ x: 0.25, y: 1, name: 'A' },
|
||||
{ x: 0.45, y: 1, name: 'B' },
|
||||
{ x: 0.25, y: 1, name: '正极' },
|
||||
{ x: 0.45, y: 1, name: '负极' },
|
||||
],
|
||||
preset: [{
|
||||
name: '微安电流表', propertyValues: { resistance: 0.05, renderFunc: '(i) => `${(i * 1000000).toFixed(0)} uA`' }
|
||||
@ -214,4 +209,30 @@ export const elements: CircuitElement[] = [
|
||||
{ key: 'renderFunc', label: '显示函数', type: 'text', default: '(i) => `${(i).toFixed(2)} A`' },
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'capacitor',
|
||||
name: '电容',
|
||||
url: capacitor,
|
||||
defaultSize: 120,
|
||||
connectionPoints: [
|
||||
{ x: 0.4, y: 0.9, name: '正极' },
|
||||
{ x: 0.6, y: 0.96, name: '负极' },
|
||||
],
|
||||
propertySchemas: [
|
||||
{ key: 'capacitance', label: '电容', type: 'number', unit: 'F', default: 0.000001 },
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'inductor',
|
||||
name: '电感',
|
||||
url: inductor,
|
||||
defaultSize: 100,
|
||||
connectionPoints: [
|
||||
{ x: 0.05, y: 0.5, name: 'A' },
|
||||
{ x: 0.95, y: 0.5, name: 'B' },
|
||||
],
|
||||
propertySchemas: [
|
||||
{ key: 'inductance', label: '电感', type: 'number', unit: 'H', default: 0.001 },
|
||||
],
|
||||
},
|
||||
]
|
||||