diff --git a/GVSDServiceServer/.gitignore b/GVSDServiceServer/.gitignore index a26b7280..54c80814 100644 --- a/GVSDServiceServer/.gitignore +++ b/GVSDServiceServer/.gitignore @@ -2,3 +2,7 @@ __pycache__/ *.pyc # 本地开发库(本服务无本地模型,仅占位) db.sqlite3 + +# venom_ui 前端子工程:依赖与构建产物不入库(构建见 venom_ui/README 或 vite build) +venom_ui/node_modules/ +venom_ui/dist/ diff --git a/GVSDServiceServer/GVSDServiceServer/settings.py b/GVSDServiceServer/GVSDServiceServer/settings.py index 83e18403..91fb724e 100644 --- a/GVSDServiceServer/GVSDServiceServer/settings.py +++ b/GVSDServiceServer/GVSDServiceServer/settings.py @@ -27,11 +27,14 @@ INSTALLED_APPS = [ 'django.contrib.staticfiles', 'rest_framework', 'apps.sub_server', + 'apps.venom', ] MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.middleware.common.CommonMiddleware', + # Venom 远端页面在 GERP 宿主内渲染,需跨源调用 /api/venom/* 与加载 /venom/* + 'apps.venom.middleware.VenomCorsMiddleware', ] ROOT_URLCONF = 'GVSDServiceServer.urls' diff --git a/GVSDServiceServer/GVSDServiceServer/urls.py b/GVSDServiceServer/GVSDServiceServer/urls.py index 8d0d86df..1caf7f9d 100644 --- a/GVSDServiceServer/GVSDServiceServer/urls.py +++ b/GVSDServiceServer/GVSDServiceServer/urls.py @@ -7,7 +7,9 @@ from apps.sub_server import views urlpatterns = [ path('', views.HomeView.as_view(), name='home'), path('health/', views.HealthView.as_view(), name='health'), - # 产品定制页的远端组件入口(宿主 GERP 运行时 import 的 ES module) + # 产品定制页的远端组件入口(宿主 GERP 运行时 import 的 ES module,构建产物托管) path('venom/remote-entry.js', views.VenomRemoteEntryView.as_view(), name='venom_remote_entry'), path('api/sub/', include('apps.sub_server.urls')), + # Venom 包管理器业务接口(远端页面跨源调用) + path('api/venom/', include('apps.venom.urls')), ] diff --git a/GVSDServiceServer/apps/sub_server/remote_pages.py b/GVSDServiceServer/apps/sub_server/remote_pages.py index 231c3808..d047bfeb 100644 --- a/GVSDServiceServer/apps/sub_server/remote_pages.py +++ b/GVSDServiceServer/apps/sub_server/remote_pages.py @@ -1,51 +1,29 @@ -"""模块:产品定制页的远端组件(ES module) +"""模块:Venom 定制页远端入口的**占位实现**(仅在 UI 未构建时使用) -宿主 GERP 前端通过 `import()` 加载本模块,并用其中的 -`createComponent(Host)` 工厂取得 Vue 组件,然后**原生渲染**(非 iframe)。 +真实产物由 `venom_ui`(Vite + Vue SFC)构建得到 `venom_ui/dist/venom-entry.js`, +由 `apps.sub_server.views.VenomRemoteEntryView` 直接托管。 -契约(与 GERP `src/apps/remoteLoader.ts` 一致): - export function createComponent(Host) -> Vue 组件 - Host = { Vue, VueRouter, Pinia, ElementPlus }(宿主注入 → 共享同一份运行时) - -真实项目里这份产物可由 Vite 打包 Vue SFC 得到;此处用渲染函数写成等价实现, -以便子服务器无需 Node 构建链即可交付。 +远端模块契约(与 GERP `src/apps/remoteLoader.ts` 一致,二者满足其一即可): + 1) 微应用(推荐,页面自带运行时): + export function mount(Element, Context) -> void + export function unmount(Element) -> void + 2) 组件工厂(宿主渲染): + export function createComponent(Host) -> Vue 组件 """ VENOM_REMOTE_ENTRY_JS = r"""/** - * Venom 定制页 —— 远端组件入口(由 GVSDServiceServer 托管) - * 契约:export function createComponent(Host) -> Vue 组件 + * 占位模块:Venom 定制页 UI 尚未构建 + * 构建方式:cd venom_ui && npm install && npm run build */ -export function createComponent(Host) { - const { h, ref } = Host.Vue - const { ElCard, ElButton, ElTag, ElMessage } = Host.ElementPlus +export function mount(Element) { + Element.innerHTML = + '
' + + 'Venom 定制页 UI 尚未构建
' + + '请在 GVSDServiceServer/venom_ui 下执行 npm install 与 npm run build 后刷新本页。' + + '
' +} - return { - name: 'VenomCustomPage', - setup() { - const count = ref(0) - return () => - h('div', { style: 'padding: 4px' }, [ - h(ElCard, { shadow: 'never' }, { - header: () => - h('div', { style: 'display: flex; align-items: center; gap: 8px' }, [ - h('b', '这是Venom'), - h(ElTag, { type: 'danger', effect: 'plain', size: 'small' }, () => 'Venom 定制页 · 由 GVSDServiceServer 托管'), - ]), - default: () => - h('div', [ - h('div', { style: 'font-size: 20px; font-weight: 700; padding: 8px 0' }, '这是Venom'), - h('div', { style: 'font-size: 13px; line-height: 2; color: var(--el-text-color-secondary)' }, [ - h('div', '该页面组件由提供者子服务器 GVSDServiceServer 托管,GERP 宿主运行时加载后原生渲染(非 iframe)。'), - h('div', ['点击次数:', h('b', String(count.value))]), - ]), - h('div', { style: 'margin-top: 12px; display: flex; gap: 8px' }, [ - h(ElButton, { type: 'primary', onClick: () => { count.value += 1 } }, () => '点我 +1'), - h(ElButton, { onClick: () => { ElMessage.success('来自 Venom 定制页') } }, () => '弹提示'), - ]), - ]), - }), - ]) - }, - } +export function unmount(Element) { + Element.innerHTML = '' } """ diff --git a/GVSDServiceServer/apps/sub_server/views.py b/GVSDServiceServer/apps/sub_server/views.py index 6d77a55d..a4f76ab2 100644 --- a/GVSDServiceServer/apps/sub_server/views.py +++ b/GVSDServiceServer/apps/sub_server/views.py @@ -4,6 +4,7 @@ """ import logging +from pathlib import Path from django.conf import settings from django.http import HttpResponse @@ -75,14 +76,22 @@ class MSyncStatusView(APIView): class VenomRemoteEntryView(APIView): - """Venom 定制页的远端组件入口(ES module,宿主 GERP 运行时 import 后原生渲染) + """Venom 定制页的远端入口(ES module,宿主 GERP 运行时 import 后原生渲染) + + 内容来自 venom_ui 的 Vite 构建产物(venom_ui/dist/venom-entry.js); + 未构建时回退到占位提示模块,避免 404/500。 宿主页面多为 https 源、本服务在 http://127.0.0.1:25090,故 ES module 加载属**跨源**, 必须放行 CORS(`Access-Control-Allow-Origin`),否则浏览器会拒绝该模块。 """ def get(self, request): - response = HttpResponse(VENOM_REMOTE_ENTRY_JS, content_type='text/javascript; charset=utf-8') + dist_file = Path(settings.BASE_DIR) / 'venom_ui' / 'dist' / 'venom-entry.js' + if dist_file.is_file(): + content = dist_file.read_text(encoding='utf-8') + else: + content = VENOM_REMOTE_ENTRY_JS + response = HttpResponse(content, content_type='text/javascript; charset=utf-8') response['Access-Control-Allow-Origin'] = '*' response['Cache-Control'] = 'no-store' return response diff --git a/GVSDServiceServer/apps/venom/__init__.py b/GVSDServiceServer/apps/venom/__init__.py new file mode 100644 index 00000000..46f14339 --- /dev/null +++ b/GVSDServiceServer/apps/venom/__init__.py @@ -0,0 +1,2 @@ +"""Venom 包管理器(提供者子服务器的产品业务) +""" diff --git a/GVSDServiceServer/apps/venom/apps.py b/GVSDServiceServer/apps/venom/apps.py new file mode 100644 index 00000000..20dddfbf --- /dev/null +++ b/GVSDServiceServer/apps/venom/apps.py @@ -0,0 +1,10 @@ +"""模块:Venom 包管理器 AppConfig""" + +from django.apps import AppConfig + + +class VenomConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'apps.venom' + verbose_name = 'Venom 包管理器' + verbose_name_plural = 'Venom 包管理器' diff --git a/GVSDServiceServer/apps/venom/middleware.py b/GVSDServiceServer/apps/venom/middleware.py new file mode 100644 index 00000000..30813131 --- /dev/null +++ b/GVSDServiceServer/apps/venom/middleware.py @@ -0,0 +1,23 @@ +"""模块:Venom 相关路径的 CORS 中间件 + +远端页面在 GERP 宿主内渲染(宿主多为 https 源),页面需跨源调用本服务的 +`/api/venom/*` 与加载 `/venom/remote-entry.js`,故统一放行 CORS。 +本服务为演示子服务器,未启用 CSRF/Session 鉴权。 +""" + + +class VenomCorsMiddleware: + SERVICE_ORIGIN = '*' + + def __init__(self, get_response): + self.get_response = get_response + + def __call__(self, request): + response = self.get_response(request) + path = request.path or '' + if path.startswith('/api/venom/') or path.startswith('/venom/'): + response['Access-Control-Allow-Origin'] = self.SERVICE_ORIGIN + response['Access-Control-Allow-Methods'] = 'GET, POST, PUT, PATCH, DELETE, OPTIONS' + response['Access-Control-Allow-Headers'] = 'Content-Type, X-Operator' + response['Access-Control-Max-Age'] = '600' + return response diff --git a/GVSDServiceServer/apps/venom/migrations/0001_initial.py b/GVSDServiceServer/apps/venom/migrations/0001_initial.py new file mode 100644 index 00000000..0f2c5ac6 --- /dev/null +++ b/GVSDServiceServer/apps/venom/migrations/0001_initial.py @@ -0,0 +1,51 @@ +# Generated by Django 6.0.5 on 2026-10-05 17:41 + +import django.db.models.deletion +import uuid +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='VenomPackage', + fields=[ + ('PackageUUID', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False, verbose_name='软件包UUID')), + ('PackageName', models.CharField(max_length=128, unique=True, verbose_name='包名(全局唯一)')), + ('PackageDesc', models.CharField(default='', max_length=512, verbose_name='包说明')), + ('ConfigText', models.TextField(default='', verbose_name='包配置内容')), + ('CreatorName', models.CharField(default='', max_length=128, verbose_name='创建人')), + ('CreateTime', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')), + ('UpdateTime', models.DateTimeField(auto_now=True, verbose_name='更新时间')), + ], + options={ + 'verbose_name': 'Venom 软件包', + 'verbose_name_plural': 'Venom 软件包', + 'db_table': 'VenomPackage', + 'ordering': ['-CreateTime'], + }, + ), + migrations.CreateModel( + name='VenomPackageRelease', + fields=[ + ('ReleaseUUID', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False, verbose_name='发布UUID')), + ('Version', models.CharField(max_length=64, verbose_name='版本号')), + ('Notes', models.TextField(default='', verbose_name='发布说明')), + ('PublisherName', models.CharField(default='', max_length=128, verbose_name='发布人')), + ('CreateTime', models.DateTimeField(auto_now_add=True, verbose_name='发布时间')), + ('Package', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='releases', to='venom.venompackage', verbose_name='所属软件包')), + ], + options={ + 'verbose_name': 'Venom 发布记录', + 'verbose_name_plural': 'Venom 发布记录', + 'db_table': 'VenomPackageRelease', + 'ordering': ['-CreateTime'], + }, + ), + ] diff --git a/GVSDServiceServer/apps/venom/migrations/__init__.py b/GVSDServiceServer/apps/venom/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/GVSDServiceServer/apps/venom/models.py b/GVSDServiceServer/apps/venom/models.py new file mode 100644 index 00000000..d412b1d8 --- /dev/null +++ b/GVSDServiceServer/apps/venom/models.py @@ -0,0 +1,53 @@ +"""模块:Venom 包管理器数据模型 + +VenomPackage —— 软件包(包名全局唯一) +VenomPackageRelease—— 包的发布历史(每次发布一条,含版本与说明) +""" + +import uuid + +from django.db import models + + +class VenomPackage(models.Model): + """软件包——包名全局唯一""" + + PackageUUID = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False, + verbose_name='软件包UUID') + PackageName = models.CharField(max_length=128, unique=True, verbose_name='包名(全局唯一)') + PackageDesc = models.CharField(max_length=512, default='', verbose_name='包说明') + ConfigText = models.TextField(default='', verbose_name='包配置内容') + CreatorName = models.CharField(max_length=128, default='', verbose_name='创建人') + CreateTime = models.DateTimeField(auto_now_add=True, verbose_name='创建时间') + UpdateTime = models.DateTimeField(auto_now=True, verbose_name='更新时间') + + class Meta: + db_table = 'VenomPackage' + ordering = ['-CreateTime'] + verbose_name = 'Venom 软件包' + verbose_name_plural = 'Venom 软件包' + + def __str__(self): + return self.PackageName + + +class VenomPackageRelease(models.Model): + """包的发布历史""" + + ReleaseUUID = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False, + verbose_name='发布UUID') + Package = models.ForeignKey(VenomPackage, on_delete=models.CASCADE, related_name='releases', + verbose_name='所属软件包') + Version = models.CharField(max_length=64, verbose_name='版本号') + Notes = models.TextField(default='', verbose_name='发布说明') + PublisherName = models.CharField(max_length=128, default='', verbose_name='发布人') + CreateTime = models.DateTimeField(auto_now_add=True, verbose_name='发布时间') + + class Meta: + db_table = 'VenomPackageRelease' + ordering = ['-CreateTime'] + verbose_name = 'Venom 发布记录' + verbose_name_plural = 'Venom 发布记录' + + def __str__(self): + return f'{self.Package.PackageName}@{self.Version}' diff --git a/GVSDServiceServer/apps/venom/urls.py b/GVSDServiceServer/apps/venom/urls.py new file mode 100644 index 00000000..9ba255c2 --- /dev/null +++ b/GVSDServiceServer/apps/venom/urls.py @@ -0,0 +1,14 @@ +"""Venom 包管理器 API 路由(挂载于 /api/venom/)""" + +from django.urls import path + +from . import views + +app_name = 'venom' + +urlpatterns = [ + path('packages/', views.PackageListView.as_view(), name='package_list'), + path('packages//', views.PackageDetailView.as_view(), name='package_detail'), + path('packages//config/', views.PackageConfigView.as_view(), name='package_config'), + path('packages//releases/', views.PackageReleaseView.as_view(), name='package_releases'), +] diff --git a/GVSDServiceServer/apps/venom/views.py b/GVSDServiceServer/apps/venom/views.py new file mode 100644 index 00000000..15c11aff --- /dev/null +++ b/GVSDServiceServer/apps/venom/views.py @@ -0,0 +1,146 @@ +"""模块:Venom 包管理器 API + +远端页面(由本服务托管、在 GERP 宿主内渲染)跨源调用以下接口: + GET /api/venom/packages/ 包列表 + POST /api/venom/packages/ 新建包(包名全局唯一) + GET /api/venom/packages// 包详情(配置页读取) + POST /api/venom/packages//config/ 保存包配置 + GET /api/venom/packages//releases/ 发布历史 + POST /api/venom/packages//releases/ 发布新版本(写历史) +""" + +import logging + +from django.db.models import Count +from django.utils.dateformat import format as date_format +from rest_framework.response import Response +from rest_framework.views import APIView + +from .models import VenomPackage, VenomPackageRelease + +logger = logging.getLogger(__name__) + + +def _ok(data=None, msg='success'): + return Response({'code': 200, 'msg': msg, 'data': data}) + + +def _err(msg, code=400, status=None): + return Response({'code': code, 'msg': msg, 'data': None}, status=status or 200) + + +def _Time(value): + return date_format(value, 'Y-m-d H:i:s') if value else '' + + +def _PackageRow(package): + return { + 'PackageUUID': str(package.PackageUUID), + 'PackageName': package.PackageName, + 'PackageDesc': package.PackageDesc or '', + 'CreatorName': package.CreatorName or '', + 'CreateTime': _Time(package.CreateTime), + 'UpdateTime': _Time(package.UpdateTime), + 'ReleaseCount': getattr(package, 'release_count', 0), + } + + +def _ReleaseRow(release): + return { + 'ReleaseUUID': str(release.ReleaseUUID), + 'Version': release.Version, + 'Notes': release.Notes or '', + 'PublisherName': release.PublisherName or '', + 'CreateTime': _Time(release.CreateTime), + } + + +def _GetPackage(PackageUUID): + return VenomPackage.objects.annotate(release_count=Count('releases')).filter( + PackageUUID=PackageUUID).first() + + +class PackageListView(APIView): + """包列表 / 新建包""" + + def get(self, request): + keyword = (request.query_params.get('Keyword') or '').strip() + qs = VenomPackage.objects.annotate(release_count=Count('releases')) + if keyword: + qs = qs.filter(PackageName__icontains=keyword) + rows = [_PackageRow(p) for p in qs] + return _ok({'list': rows, 'total': len(rows)}) + + def post(self, request): + name = (request.data.get('PackageName') or '').strip() + if not name: + return _err('请填写包名') + if len(name) > 128: + return _err('包名过长(最多 128 字)') + if VenomPackage.objects.filter(PackageName=name).exists(): + return _err(f'包名「{name}」已存在(包名必须全局唯一)') + package = VenomPackage.objects.create( + PackageName=name, + PackageDesc=(request.data.get('PackageDesc') or '').strip()[:512], + ConfigText=request.data.get('ConfigText') or '', + CreatorName=(request.data.get('CreatorName') or '').strip()[:128], + ) + package = _GetPackage(package.PackageUUID) + return _ok(_PackageRow(package), msg='软件包已创建') + + +class PackageDetailView(APIView): + """包详情(配置页读取)""" + + def get(self, request, package_uuid): + package = _GetPackage(package_uuid) + if package is None: + return _err('软件包不存在', 404) + row = _PackageRow(package) + row['ConfigText'] = package.ConfigText or '' + return _ok(row) + + +class PackageConfigView(APIView): + """保存包配置""" + + def post(self, request, package_uuid): + package = VenomPackage.objects.filter(PackageUUID=package_uuid).first() + if package is None: + return _err('软件包不存在', 404) + if 'PackageDesc' in request.data: + package.PackageDesc = (request.data.get('PackageDesc') or '').strip()[:512] + if 'ConfigText' in request.data: + package.ConfigText = request.data.get('ConfigText') or '' + package.save(update_fields=['PackageDesc', 'ConfigText', 'UpdateTime']) + row = _PackageRow(_GetPackage(package.PackageUUID)) + row['ConfigText'] = package.ConfigText or '' + return _ok(row, msg='配置已保存') + + +class PackageReleaseView(APIView): + """发布历史 / 发布新版本""" + + def get(self, request, package_uuid): + package = VenomPackage.objects.filter(PackageUUID=package_uuid).first() + if package is None: + return _err('软件包不存在', 404) + rows = [_ReleaseRow(r) for r in package.releases.all()] + return _ok({'PackageName': package.PackageName, 'list': rows, 'total': len(rows)}) + + def post(self, request, package_uuid): + package = VenomPackage.objects.filter(PackageUUID=package_uuid).first() + if package is None: + return _err('软件包不存在', 404) + version = (request.data.get('Version') or '').strip() + if not version: + return _err('请填写版本号') + if len(version) > 64: + return _err('版本号过长(最多 64 字)') + release = VenomPackageRelease.objects.create( + Package=package, + Version=version, + Notes=request.data.get('Notes') or '', + PublisherName=(request.data.get('PublisherName') or '').strip()[:128], + ) + return _ok(_ReleaseRow(release), msg='已发布') diff --git a/GVSDServiceServer/venom_ui/package-lock.json b/GVSDServiceServer/venom_ui/package-lock.json new file mode 100644 index 00000000..5734a16e --- /dev/null +++ b/GVSDServiceServer/venom_ui/package-lock.json @@ -0,0 +1,1251 @@ +{ + "name": "venom-ui", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "venom-ui", + "version": "1.0.0", + "dependencies": { + "element-plus": "^2.14.3", + "vue": "^3.5.40" + }, + "devDependencies": { + "@vitejs/plugin-vue": "^6.0.8", + "vite": "^8.2.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.9", + "resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.29.9.tgz", + "integrity": "sha512-CjXrNHTnvqBVqHgdBysY3vk2T8tpJHb5/RMeHJBTyVa9xgugCB0CJTx/3oO8RV2QRQP391RWpB7D6hLjm8V9uA==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.8" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.8", + "resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.29.8.tgz", + "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@ctrl/tinycolor": { + "version": "4.2.1", + "resolved": "https://registry.npmmirror.com/@ctrl/tinycolor/-/tinycolor-4.2.1.tgz", + "integrity": "sha512-Vh5uy9Y1JBMId6J1f68TMXnZrTCvNdo9Fu2k0d1YnJngR+sM5kWTKl441c/3TFs+cG0NWOjRWgQ/iaWhbYx+7A==", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/@element-plus/icons-vue": { + "version": "2.3.2", + "resolved": "https://registry.npmmirror.com/@element-plus/icons-vue/-/icons-vue-2.3.2.tgz", + "integrity": "sha512-OzIuTaIfC8QXEPmJvB4Y4kw34rSXdCJzxcD1kFStBvr8bK6X1zQAYDo0CNMjojnfTqRQCJ0I7prlErcoRiET2A==", + "license": "MIT", + "peerDependencies": { + "vue": "^3.2.0" + } + }, + "node_modules/@floating-ui/core": { + "version": "1.8.0", + "resolved": "https://registry.npmmirror.com/@floating-ui/core/-/core-1.8.0.tgz", + "integrity": "sha512-0CIZ5itps/8x7BG8dEIhs53BvCUH2PCoogtakwRTut+Arm58sJooJ0AuZhLw2HJYIR5cMLNPBSS728sPho2khQ==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.12" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.8.0", + "resolved": "https://registry.npmmirror.com/@floating-ui/dom/-/dom-1.8.0.tgz", + "integrity": "sha512-yXSrzeHZBTZadLOlfyhCkJHNeLJnHRnRInwdZ40L7ZiaAtrBwoYlsDrX3v5zB1Utk7CLfzcOVnVVWoXEky7Ceg==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.8.0", + "@floating-ui/utils": "^0.2.12" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.12", + "resolved": "https://registry.npmmirror.com/@floating-ui/utils/-/utils-0.2.12.tgz", + "integrity": "sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww==", + "license": "MIT" + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.6.0", + "resolved": "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz", + "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", + "license": "MIT" + }, + "node_modules/@oxc-project/types": { + "version": "0.152.0", + "resolved": "https://registry.npmmirror.com/@oxc-project/types/-/types-0.152.0.tgz", + "integrity": "sha512-oM/5rLBm2tPkg0iBgkH/FOeR3PCDpY19GTgAZjMFM8h9WI9VW7cLgzp6nwtarYKmovavIQZ+Fe/RKX/8C8O/Rw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/oxc-project" + } + }, + "node_modules/@popperjs/core": { + "name": "@sxzz/popperjs-es", + "version": "2.11.8", + "resolved": "https://registry.npmmirror.com/@sxzz/popperjs-es/-/popperjs-es-2.11.8.tgz", + "integrity": "sha512-wOwESXvvED3S8xBmcPWHs2dUuzrE4XiZeFu7e1hROIJkm02a49N120pmOXxY33sBb6hArItm5W5tcg1cBtV+HQ==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@rolldown/binding-android-arm-eabi": { + "version": "1.2.12", + "resolved": "https://registry.npmmirror.com/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.12.tgz", + "integrity": "sha512-dB/a1214qKfHMXCpgqR4OZT+jS4kTyEXbQGJPqzobt5EwH5rX080pxE37alt3RzvR1bf1Yz/yGqRfrYAxuPw0A==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.2.12", + "resolved": "https://registry.npmmirror.com/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.12.tgz", + "integrity": "sha512-7KHFgQ5VJxIHcLlrwrc3Xbds7oTNQT7Pgi9gQCJKrd2VGab/UksIOYp6VD8MzCstGxOKMgNamPwUCfxPdP1OHg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.2.12", + "resolved": "https://registry.npmmirror.com/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.12.tgz", + "integrity": "sha512-3YIhqHD96nA5SaYNRBR16HnGv4oavZvXfD/ayHM+oYZ0WD/8lBAtf6zQua4kEyAvpqrluKXl0lnOBoiNby7x9w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.2.12", + "resolved": "https://registry.npmmirror.com/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.12.tgz", + "integrity": "sha512-UuuJ35MFw4gmFOrE9pEqIV+K3syIKveph+Qc1/ljHZVdoDW4pz/JHR/eMVom+TZGl/5OOvGJOWaOCVt3ZfqhxA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.2.12", + "resolved": "https://registry.npmmirror.com/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.12.tgz", + "integrity": "sha512-uMvssit0a4W+/7D8CbHUvG719mH3R2jwXAlh/XcPvuHTE0g++LymF88DCGNX0HM2rBOn0xrzgXktIB6fLSJBTQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.2.12", + "resolved": "https://registry.npmmirror.com/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.12.tgz", + "integrity": "sha512-XcFu0R0xWnwzSf4IQgFH1rJIckPN1pLy2R+4r9IDB7Yfu/ys9cVqfa4pBrMHj7a3gl8mIR4nRNPg0e5IvEVs6g==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.2.12", + "resolved": "https://registry.npmmirror.com/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.12.tgz", + "integrity": "sha512-260UrKgn8tz39ak+SMDOirKzr7V04M9dWPw5llW00SwBivCZoWcRBKV1d8cXnRkUmSZA3BdiUmBHWk7734Ulpw==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.2.12", + "resolved": "https://registry.npmmirror.com/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.12.tgz", + "integrity": "sha512-5YK1I9SqDkbPgc1IA8BgDl34suqUS2q0KWnBrirm0E51YjOs6eo6dV6jbQfNE/argHRSvd0QUGgtpIoYx+WWpw==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.2.12", + "resolved": "https://registry.npmmirror.com/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.12.tgz", + "integrity": "sha512-Rkcrmp7eFRg74yL5fXEU91JEWbdEPLevWwGtXpmhbjlD1StScbWTmO94Bhly+Mo+ketKYkdmM1vNUKeWSlx8cQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.2.12", + "resolved": "https://registry.npmmirror.com/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.12.tgz", + "integrity": "sha512-qvK4DuAsQc2BSjlx+Xr+IzOIvvxbGZqxFwdWfG6F518Erj0GGISyQbJ6pIappnOxlNPzNHvo/L0BwB30GZ+zVw==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.2.12", + "resolved": "https://registry.npmmirror.com/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.12.tgz", + "integrity": "sha512-Q9uLBO53Xd4QIq1WOycVQyPP1O4HhraEV2qqb3uTrnVw6QZih9duY4vNXOivL1xoUS1/z+W8eF4NMfl2a8Sdjw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.2.12", + "resolved": "https://registry.npmmirror.com/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.12.tgz", + "integrity": "sha512-3IBxWFMjbOZskDPKv8Lf9BCnahlKuHthWkYnyIxOH/QcJrFcS4EmcenthApkwr/5+nEqZlLzeYbxeMaX7A5u4g==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.2.12", + "resolved": "https://registry.npmmirror.com/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.12.tgz", + "integrity": "sha512-xtX61xg4LKPkPWilZU1ynKClz5Gj4bf74LML4r3eVLWumKnGjoEr1OSHQhMdbBDoYTi+yjrujvpZe2pUnqCrrA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.2.12", + "resolved": "https://registry.npmmirror.com/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.12.tgz", + "integrity": "sha512-At7fPB6PCaIjzgIhEZFxuT+BBFqiQibJDT4d3PhiR3f4E7bbMZF4aKblbFfEM3sETRDd1YiQx/+U/g/B/ou5Ew==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.2.12", + "resolved": "https://registry.npmmirror.com/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.12.tgz", + "integrity": "sha512-WIw2haVKwjuYdXkHaoC0mF8Le71TuCBxjrdKqLbJGctbBABj+ClfmNvtbOnzpq3RokNo5+V1qhtSzJyXorsklQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/lodash": { + "version": "4.17.25", + "resolved": "https://registry.npmmirror.com/@types/lodash/-/lodash-4.17.25.tgz", + "integrity": "sha512-+K1NIO8I+F9/wNulfVvu23QYd0Pe9/OCqRrim4NoYIf1VoEDL90Ve4ClzpyqBLc7NpGGWRvYNCKZ1BE/Jpf8dQ==", + "license": "MIT" + }, + "node_modules/@types/lodash-es": { + "version": "4.17.12", + "resolved": "https://registry.npmmirror.com/@types/lodash-es/-/lodash-es-4.17.12.tgz", + "integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==", + "license": "MIT", + "dependencies": { + "@types/lodash": "*" + } + }, + "node_modules/@types/web-bluetooth": { + "version": "0.0.21", + "resolved": "https://registry.npmmirror.com/@types/web-bluetooth/-/web-bluetooth-0.0.21.tgz", + "integrity": "sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==", + "license": "MIT" + }, + "node_modules/@vitejs/plugin-vue": { + "version": "6.0.9", + "resolved": "https://registry.npmmirror.com/@vitejs/plugin-vue/-/plugin-vue-6.0.9.tgz", + "integrity": "sha512-rD/MORlhaZMlXWW0rEn4FB4wMinWC0z/D7Ye160S5+Rs1mC8ZDAdcDp4SjKfUhG5t8q1ktcPVw4xuTkPRlzrSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rolldown/pluginutils": "^1.0.1" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0", + "vue": "^3.2.25" + } + }, + "node_modules/@vue/compiler-core": { + "version": "3.5.43", + "resolved": "https://registry.npmmirror.com/@vue/compiler-core/-/compiler-core-3.5.43.tgz", + "integrity": "sha512-zdiLhnbe1QQqgDT8xZMpNmyqZ3qlI+/Q/FHQco57Kwl/b05HhCzN6eVGN9QU9rbga4CrS0H5SYY8VGHZCt/1Hg==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.8", + "@vue/shared": "3.5.43", + "entities": "^7.0.1", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-dom": { + "version": "3.5.43", + "resolved": "https://registry.npmmirror.com/@vue/compiler-dom/-/compiler-dom-3.5.43.tgz", + "integrity": "sha512-PEZoAk3NQmsn/ejMzSOCyTYqwGqczrWm70PuhBKjjv1+TCoQAaO/zOqNwjV+honlNstT5ILxtc+8r8UUfj+iEQ==", + "license": "MIT", + "dependencies": { + "@vue/compiler-core": "3.5.43", + "@vue/shared": "3.5.43" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.5.43", + "resolved": "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-3.5.43.tgz", + "integrity": "sha512-FCbrG3XNCRl+js3huuKx4IVHBLTvMkJhVepjbxSPu1gn4yWLaYtGNQdjJGZaMytXB6qb76qQDDmDSLy/vkmleQ==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.8", + "@vue/compiler-core": "3.5.43", + "@vue/compiler-dom": "3.5.43", + "@vue/compiler-ssr": "3.5.43", + "@vue/shared": "3.5.43", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.21", + "postcss": "^8.5.28", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.5.43", + "resolved": "https://registry.npmmirror.com/@vue/compiler-ssr/-/compiler-ssr-3.5.43.tgz", + "integrity": "sha512-GF62orf7KiJX9RqrHNGrYBudsQGD0OhJ5nDs90O8UiDuS40+YMYomiXu6w6EuvtXuRDc3MSNis3EaaSKAVSWpg==", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.43", + "@vue/shared": "3.5.43" + } + }, + "node_modules/@vue/reactivity": { + "version": "3.5.43", + "resolved": "https://registry.npmmirror.com/@vue/reactivity/-/reactivity-3.5.43.tgz", + "integrity": "sha512-G/c9GyOZNI2jVaaS6OX1EF1SSFSv7H0ERqNTl4+DTFMlZmB5eVAB53aLQNam/7NL2NPtaDD7RdVrzf8uJzMuOA==", + "license": "MIT", + "dependencies": { + "@vue/shared": "3.5.43" + } + }, + "node_modules/@vue/runtime-core": { + "version": "3.5.43", + "resolved": "https://registry.npmmirror.com/@vue/runtime-core/-/runtime-core-3.5.43.tgz", + "integrity": "sha512-hU6U6VnVhBGQDpvlnnDlIB8ZGJBiOcgk2lh/0InltHiz3D8oSkluvuvY+do1G2H3+udeKFsmaBlgVYP7gXQzEw==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.43", + "@vue/shared": "3.5.43" + } + }, + "node_modules/@vue/runtime-dom": { + "version": "3.5.43", + "resolved": "https://registry.npmmirror.com/@vue/runtime-dom/-/runtime-dom-3.5.43.tgz", + "integrity": "sha512-Bb2Jc0YjjJdMt1SJmb9b2L/IWd3I8lIT9x9eS/xvvP9CiVgna0ffua74xKRmt4/uSJ+0r4iN8ex1jrqkhQGWQw==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.43", + "@vue/runtime-core": "3.5.43", + "@vue/shared": "3.5.43", + "csstype": "^3.2.3" + } + }, + "node_modules/@vue/server-renderer": { + "version": "3.5.43", + "resolved": "https://registry.npmmirror.com/@vue/server-renderer/-/server-renderer-3.5.43.tgz", + "integrity": "sha512-l2Ygjv9NehV94PSBxNWsAHC0j/eIIKbn92mBuWXAPGLnn6HfJ6MH5ubsd+Nk0YoZ5FRuxWI1P2VSoh+dbPQhCQ==", + "license": "MIT", + "dependencies": { + "@vue/compiler-ssr": "3.5.43", + "@vue/runtime-dom": "3.5.43", + "@vue/shared": "3.5.43" + } + }, + "node_modules/@vue/shared": { + "version": "3.5.43", + "resolved": "https://registry.npmmirror.com/@vue/shared/-/shared-3.5.43.tgz", + "integrity": "sha512-uksS7YGMR5NZyr4JNq0Rp+QyLns0ueaz20KwzIPW9R0LH1Vnt4E+XUM29PNseEbf1www2gOuhuDi5AKOIXag9Q==", + "license": "MIT" + }, + "node_modules/@vueuse/core": { + "version": "15.0.0", + "resolved": "https://registry.npmmirror.com/@vueuse/core/-/core-15.0.0.tgz", + "integrity": "sha512-Zv67h5mrk7YHDJsRObx+DXaCBz6RKBUpxqLesJ+3xZNPG6yuQs7ja7kg3veFrrouYLWAqydQ7CwGEbLVxB43Ng==", + "license": "MIT", + "dependencies": { + "@types/web-bluetooth": "^0.0.21", + "@vueuse/metadata": "15.0.0", + "@vueuse/shared": "15.0.0" + }, + "engines": { + "node": ">=22" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "vue": "^3.5.0" + } + }, + "node_modules/@vueuse/metadata": { + "version": "15.0.0", + "resolved": "https://registry.npmmirror.com/@vueuse/metadata/-/metadata-15.0.0.tgz", + "integrity": "sha512-sfWE5LADAKJ0KnjtGliMdSN8Ij/L7uP6rXIZlgPloAI4zvvefbw6H5Lt7KJA6RqQOYgVqWF5Guj50HHMIzygBg==", + "license": "MIT", + "engines": { + "node": ">=22" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/shared": { + "version": "15.0.0", + "resolved": "https://registry.npmmirror.com/@vueuse/shared/-/shared-15.0.0.tgz", + "integrity": "sha512-vbNXhGrbV53xPOMSyOzMHQRvhMgZf7oNDw2RChUetVxwTIEkInQ1joZ9JbT0G3z2n2AJNjvmCWeM9ySYrnvogA==", + "license": "MIT", + "engines": { + "node": ">=22" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "vue": "^3.5.0" + } + }, + "node_modules/async-validator": { + "version": "4.2.5", + "resolved": "https://registry.npmmirror.com/async-validator/-/async-validator-4.2.5.tgz", + "integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==", + "license": "MIT" + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmmirror.com/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "license": "MIT" + }, + "node_modules/dayjs": { + "version": "1.11.23", + "resolved": "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.23.tgz", + "integrity": "sha512-QDTCU0M0MxR3hQfnlDJfwekQiaanm1ubOD231u73WBckQ/fsamwRLiE2GBz6D3a/xF1NgfiDLJjXBa1hYOYTtQ==", + "license": "MIT" + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmmirror.com/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/element-plus": { + "version": "2.14.7", + "resolved": "https://registry.npmmirror.com/element-plus/-/element-plus-2.14.7.tgz", + "integrity": "sha512-lrG7pZyCS+mpCNVpzxxyu5r35+T6V0hzkAeIwn7HA6to772XSTHKuYCZG51OfzlqaxGbNegLxs650zAF1j43gA==", + "license": "MIT", + "dependencies": { + "@ctrl/tinycolor": "^4.2.1", + "@element-plus/icons-vue": "^2.3.2", + "@floating-ui/dom": "^1.8.0", + "@popperjs/core": "npm:@sxzz/popperjs-es@^2.11.8", + "@types/lodash": "^4.17.24", + "@types/lodash-es": "^4.17.12", + "@vueuse/core": "15.0.0", + "async-validator": "^4.2.5", + "dayjs": "^1.11.20", + "lodash": "^4.18.1", + "lodash-es": "^4.18.1", + "lodash-unified": "^1.0.3", + "memoize-one": "^6.0.0", + "normalize-wheel-es": "^1.2.0", + "vue-component-type-helpers": "^3.3.11" + }, + "peerDependencies": { + "vue": "^3.3.7" + } + }, + "node_modules/entities": { + "version": "7.0.1", + "resolved": "https://registry.npmmirror.com/entities/-/entities-7.0.1.tgz", + "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "license": "MIT" + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmmirror.com/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/lightningcss": { + "version": "1.33.0", + "resolved": "https://registry.npmmirror.com/lightningcss/-/lightningcss-1.33.0.tgz", + "integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.33.0", + "lightningcss-darwin-arm64": "1.33.0", + "lightningcss-darwin-x64": "1.33.0", + "lightningcss-freebsd-x64": "1.33.0", + "lightningcss-linux-arm-gnueabihf": "1.33.0", + "lightningcss-linux-arm64-gnu": "1.33.0", + "lightningcss-linux-arm64-musl": "1.33.0", + "lightningcss-linux-x64-gnu": "1.33.0", + "lightningcss-linux-x64-musl": "1.33.0", + "lightningcss-win32-arm64-msvc": "1.33.0", + "lightningcss-win32-x64-msvc": "1.33.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmmirror.com/lightningcss-android-arm64/-/lightningcss-android-arm64-1.33.0.tgz", + "integrity": "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmmirror.com/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.33.0.tgz", + "integrity": "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmmirror.com/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.33.0.tgz", + "integrity": "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmmirror.com/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.33.0.tgz", + "integrity": "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.33.0", + "resolved": "https://registry.npmmirror.com/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.33.0.tgz", + "integrity": "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmmirror.com/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.33.0.tgz", + "integrity": "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmmirror.com/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.33.0.tgz", + "integrity": "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmmirror.com/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.33.0.tgz", + "integrity": "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmmirror.com/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.33.0.tgz", + "integrity": "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmmirror.com/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.33.0.tgz", + "integrity": "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmmirror.com/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz", + "integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "license": "MIT" + }, + "node_modules/lodash-es": { + "version": "4.18.1", + "resolved": "https://registry.npmmirror.com/lodash-es/-/lodash-es-4.18.1.tgz", + "integrity": "sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==", + "license": "MIT" + }, + "node_modules/lodash-unified": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/lodash-unified/-/lodash-unified-1.0.3.tgz", + "integrity": "sha512-WK9qSozxXOD7ZJQlpSqOT+om2ZfcT4yO+03FuzAHD0wF6S0l0090LRPDx3vhTTLZ8cFKpBn+IOcVXK6qOcIlfQ==", + "license": "MIT", + "peerDependencies": { + "@types/lodash-es": "*", + "lodash": "*", + "lodash-es": "*" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/memoize-one": { + "version": "6.0.0", + "resolved": "https://registry.npmmirror.com/memoize-one/-/memoize-one-6.0.0.tgz", + "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==", + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.19", + "resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.19.tgz", + "integrity": "sha512-Y2tUNy4ouw6tq5oDSKeQYGOyhkUBhNOcGV/02KC+6kd9eDGqdZd++mjMiIDilrBYvjEnCYvVtsuHCuP+okSfug==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/normalize-wheel-es": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/normalize-wheel-es/-/normalize-wheel-es-1.2.0.tgz", + "integrity": "sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw==", + "license": "BSD-3-Clause" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.7", + "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.29", + "resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.5.29.tgz", + "integrity": "sha512-49cGhUbXj8Qenv0iTMxA1cFBzxXoctpC9Ujd77t1WcbJIr6nF/eI7g/8MgxrYldFRuAXvja7xQRwavoW7kgrxQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.19", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/rolldown": { + "version": "1.2.12", + "resolved": "https://registry.npmmirror.com/rolldown/-/rolldown-1.2.12.tgz", + "integrity": "sha512-8wafseiaG80xmXSfqidUNqZcylTlhmPZZt+za2m+js2sFZ8dTNlhIOV2WcbIPx2hgwPBJpEUGFAMZ9bgBBLTSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.152.0", + "@rolldown/pluginutils": "^1.0.0" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm-eabi": "1.2.12", + "@rolldown/binding-android-arm64": "1.2.12", + "@rolldown/binding-darwin-arm64": "1.2.12", + "@rolldown/binding-darwin-x64": "1.2.12", + "@rolldown/binding-freebsd-x64": "1.2.12", + "@rolldown/binding-linux-arm-gnueabihf": "1.2.12", + "@rolldown/binding-linux-arm64-gnu": "1.2.12", + "@rolldown/binding-linux-arm64-musl": "1.2.12", + "@rolldown/binding-linux-ppc64-gnu": "1.2.12", + "@rolldown/binding-linux-s390x-gnu": "1.2.12", + "@rolldown/binding-linux-x64-gnu": "1.2.12", + "@rolldown/binding-linux-x64-musl": "1.2.12", + "@rolldown/binding-openharmony-arm64": "1.2.12", + "@rolldown/binding-win32-arm64-msvc": "1.2.12", + "@rolldown/binding-win32-x64-msvc": "1.2.12" + } + }, + "node_modules/source-map-js": { + "version": "1.2.2", + "resolved": "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.2.2.tgz", + "integrity": "sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmmirror.com/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/vite": { + "version": "8.3.2", + "resolved": "https://registry.npmmirror.com/vite/-/vite-8.3.2.tgz", + "integrity": "sha512-SQr1x6W5vVSbROg7vsyXIaxK9b0G7zsT68acdWWRmnBUsgDieLCRG+Rep9WdZgcposvv/GSnr4GUUBqB3vXq6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "lightningcss": "^1.33.0", + "picomatch": "^4.0.7", + "postcss": "^8.5.28", + "rolldown": "~1.2.11", + "tinyglobby": "^0.2.17" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.7.1", + "esbuild": "^0.27.0 || ^0.28.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vue": { + "version": "3.5.43", + "resolved": "https://registry.npmmirror.com/vue/-/vue-3.5.43.tgz", + "integrity": "sha512-o5qZoksdnjIKvW1srZ3ab7pcDNYAerBjRe54D0LBLfRdCYFrSgBHVXokMas35czQc0//lmx4/tuY4ZNQ+Rf2Ng==", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.43", + "@vue/compiler-sfc": "3.5.43", + "@vue/runtime-dom": "3.5.43", + "@vue/server-renderer": "3.5.43", + "@vue/shared": "3.5.43" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/vue-component-type-helpers": { + "version": "3.3.12", + "resolved": "https://registry.npmmirror.com/vue-component-type-helpers/-/vue-component-type-helpers-3.3.12.tgz", + "integrity": "sha512-HwCqmgTfLFskQc4P5TRnbduCMyPat2Ezu0elLWOGn0dD/6BKHP15B5bxce6aDi+E4kblPtru8amIBQzu0Di3qQ==", + "license": "MIT" + } + } +} diff --git a/GVSDServiceServer/venom_ui/package.json b/GVSDServiceServer/venom_ui/package.json new file mode 100644 index 00000000..dfc84679 --- /dev/null +++ b/GVSDServiceServer/venom_ui/package.json @@ -0,0 +1,18 @@ +{ + "name": "venom-ui", + "private": true, + "version": "1.0.0", + "description": "Venom 包管理器定制页(远端微前端产物,由 GVSDServiceServer 托管)", + "type": "module", + "scripts": { + "build": "vite build" + }, + "dependencies": { + "element-plus": "^2.14.3", + "vue": "^3.5.40" + }, + "devDependencies": { + "@vitejs/plugin-vue": "^6.0.8", + "vite": "^8.2.0" + } +} diff --git a/GVSDServiceServer/venom_ui/src/App.vue b/GVSDServiceServer/venom_ui/src/App.vue new file mode 100644 index 00000000..c80f6b15 --- /dev/null +++ b/GVSDServiceServer/venom_ui/src/App.vue @@ -0,0 +1,322 @@ + + + + + diff --git a/GVSDServiceServer/venom_ui/src/api.ts b/GVSDServiceServer/venom_ui/src/api.ts new file mode 100644 index 00000000..fa563079 --- /dev/null +++ b/GVSDServiceServer/venom_ui/src/api.ts @@ -0,0 +1,78 @@ +/** Venom 包管理器 API 客户端 + * + * 远端模块由 GVSDServiceServer 自身托管,故用 `import.meta.url` 推断服务地址, + * 无需宿主额外注入(跨源由子服务器的 CORS 中间件放行)。 + */ + +const API_BASE = (() => { + try { + return new URL('/api/venom', import.meta.url).toString() + } catch { + return '/api/venom' + } +})() + +export interface VenomPackageItem { + PackageUUID: string + PackageName: string + PackageDesc: string + CreatorName: string + CreateTime: string + UpdateTime: string + ReleaseCount: number + ConfigText?: string +} + +/** 宿主注入的上下文(当前登录人/公司,用于「创建人」「发布人」) */ +export interface RemoteContext { + UserUUID?: string + UserName?: string + CompanyUUID?: string + CompanyName?: string +} + +export interface VenomReleaseItem { + ReleaseUUID: string + Version: string + Notes: string + PublisherName: string + CreateTime: string +} + +async function request(method: string, path: string, body?: unknown): Promise { + const response = await fetch(`${API_BASE}${path}`, { + method, + headers: { 'Content-Type': 'application/json' }, + body: body === undefined ? undefined : JSON.stringify(body), + }) + let payload: { code?: number; msg?: string; data?: unknown } | null = null + try { + payload = await response.json() + } catch { + throw new Error(`服务响应异常(HTTP ${response.status})`) + } + if (!payload || payload.code !== 200) { + throw new Error(payload?.msg || `请求失败(HTTP ${response.status})`) + } + return payload.data as T +} + +export const venomApi = { + listPackages: (keyword = '') => + request<{ list: VenomPackageItem[]; total: number }>( + 'GET', + `/packages/${keyword ? `?Keyword=${encodeURIComponent(keyword)}` : ''}`, + ), + createPackage: (data: { PackageName: string; PackageDesc: string; ConfigText: string; CreatorName: string }) => + request('POST', '/packages/', data), + getPackage: (uuid: string) => request('GET', `/packages/${uuid}/`), + saveConfig: (uuid: string, data: { PackageDesc: string; ConfigText: string }) => + request('POST', `/packages/${uuid}/config/`, data), + listReleases: (uuid: string) => + request<{ PackageName: string; list: VenomReleaseItem[]; total: number }>( + 'GET', + `/packages/${uuid}/releases/`, + ), + publishRelease: (uuid: string, data: { Version: string; Notes: string; PublisherName: string }) => + request('POST', `/packages/${uuid}/releases/`, data), +} diff --git a/GVSDServiceServer/venom_ui/src/main.ts b/GVSDServiceServer/venom_ui/src/main.ts new file mode 100644 index 00000000..22599fc7 --- /dev/null +++ b/GVSDServiceServer/venom_ui/src/main.ts @@ -0,0 +1,33 @@ +/** + * Venom 定制页远端入口(微应用契约) + * + * 宿主 GERP 通过 `import()` 加载本模块,调用: + * mount(Element, Context) —— 在给定容器内挂载本页面(自带运行时) + * unmount(Element) —— 卸载并清空容器 + * + * 与宿主组件工厂契约 createComponent(Host) 并列,二者满足其一即可(见 GERP remoteLoader.ts)。 + * 本页面自带 Vue/Element Plus,运行时可与会话完全自洽。 + */ +import { createApp, type App as VueApp } from 'vue' +import ElementPlus from 'element-plus' +import 'element-plus/dist/index.css' +import 'element-plus/theme-chalk/dark/css-vars.css' + +import App from './App.vue' +import type { RemoteContext } from './api' + +let app: VueApp | null = null + +export function mount(Element: HTMLElement, Context: RemoteContext = {}): void { + app = createApp(App, { Context: Context || {} }) + app.use(ElementPlus) + app.mount(Element) +} + +export function unmount(Element: HTMLElement): void { + if (app) { + app.unmount() + app = null + } + Element.innerHTML = '' +} diff --git a/GVSDServiceServer/venom_ui/vite.config.ts b/GVSDServiceServer/venom_ui/vite.config.ts new file mode 100644 index 00000000..f475d8f8 --- /dev/null +++ b/GVSDServiceServer/venom_ui/vite.config.ts @@ -0,0 +1,45 @@ +import { defineConfig, type Plugin } from 'vite' +import vue from '@vitejs/plugin-vue' + +/** + * 把构建出的 CSS 内联进 JS(远端入口要求单文件:宿主只 import 这一个 ES module)。 + * 产物在页面加载时自动注入