diff --git a/web/apps/web-ele/index.html b/web/apps/web-ele/index.html
index 2b59b8d..54b03c9 100644
--- a/web/apps/web-ele/index.html
+++ b/web/apps/web-ele/index.html
@@ -11,22 +11,8 @@
name="viewport"
content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=0"
/>
-
<%= VITE_APP_TITLE %>
-
-
+
diff --git a/web/apps/web-ele/src/views/_core/authentication/login.vue b/web/apps/web-ele/src/views/_core/authentication/login.vue
index ebee0be..0534853 100644
--- a/web/apps/web-ele/src/views/_core/authentication/login.vue
+++ b/web/apps/web-ele/src/views/_core/authentication/login.vue
@@ -123,6 +123,7 @@ const formSchema = computed((): VbenFormSchema[] => {
{
component: 'VbenInput',
componentProps: {
+ autocomplete: 'username',
placeholder: $t('authentication.usernameTip'),
},
defaultValue: '',
@@ -133,6 +134,7 @@ const formSchema = computed((): VbenFormSchema[] => {
{
component: 'VbenInputPassword',
componentProps: {
+ autocomplete: 'current-password',
placeholder: $t('authentication.passwordTip'),
},
defaultValue: '',
diff --git a/web/scripts/serve-web-ele-dist.mjs b/web/scripts/serve-web-ele-dist.mjs
new file mode 100644
index 0000000..e324e9c
--- /dev/null
+++ b/web/scripts/serve-web-ele-dist.mjs
@@ -0,0 +1,112 @@
+import { createReadStream } from 'node:fs';
+import { stat } from 'node:fs/promises';
+import http from 'node:http';
+import path from 'node:path';
+import { fileURLToPath } from 'node:url';
+
+const root = fileURLToPath(new URL('../apps/web-ele/dist', import.meta.url));
+const host = process.env.HOST || '127.0.0.1';
+const port = Number(process.env.PORT || 5777);
+const basePath = process.env.BASE_PATH || '/ai-agent-admin';
+const apiPrefix = `${basePath}/basic-api`;
+const rootApiPrefix = '/basic-api';
+const apiTarget =
+ process.env.API_TARGET || 'http://124.220.21.25/zq-ai-admin/basic-api';
+
+const mime = {
+ '.css': 'text/css; charset=utf-8',
+ '.html': 'text/html; charset=utf-8',
+ '.ico': 'image/x-icon',
+ '.js': 'application/javascript; charset=utf-8',
+ '.json': 'application/json; charset=utf-8',
+ '.mjs': 'application/javascript; charset=utf-8',
+ '.mp3': 'audio/mpeg',
+ '.png': 'image/png',
+ '.svg': 'image/svg+xml',
+};
+
+async function exists(filePath) {
+ try {
+ return (await stat(filePath)).isFile();
+ } catch {
+ return false;
+ }
+}
+
+async function proxy(req, res) {
+ const targetBase = apiTarget.replace(/\/$/, '');
+ const apiPath = req.url.startsWith(apiPrefix)
+ ? req.url.replace(apiPrefix, '')
+ : req.url.replace(rootApiPrefix, '');
+ const target = new URL(`${targetBase}${apiPath}`);
+ const headers = { ...req.headers };
+ delete headers.host;
+
+ let upstream;
+ try {
+ upstream = await fetch(target, {
+ body: ['GET', 'HEAD'].includes(req.method) ? undefined : req,
+ duplex: 'half',
+ headers,
+ method: req.method,
+ });
+ } catch (error) {
+ res.writeHead(502, { 'Content-Type': 'text/plain; charset=utf-8' });
+ res.end(`Proxy upstream unavailable: ${target}\n${error.message}`);
+ return;
+ }
+
+ res.writeHead(upstream.status, Object.fromEntries(upstream.headers));
+ if (upstream.body) {
+ res.end(Buffer.from(await upstream.arrayBuffer()));
+ } else {
+ res.end();
+ }
+}
+
+async function serve(req, res) {
+ const url = new URL(req.url || '/', `http://${host}:${port}`);
+ if (
+ url.pathname.startsWith(apiPrefix) ||
+ url.pathname.startsWith(rootApiPrefix)
+ ) {
+ await proxy(req, res);
+ return;
+ }
+
+ if (url.pathname === '/' || url.pathname === '') {
+ res.writeHead(302, { Location: `${basePath}/` });
+ res.end();
+ return;
+ }
+
+ if (!url.pathname.startsWith(basePath)) {
+ res.writeHead(404);
+ res.end('Not Found');
+ return;
+ }
+
+ let rel = url.pathname.slice(basePath.length) || '/index.html';
+ if (rel === '/') rel = '/index.html';
+
+ let filePath = path.join(root, rel);
+ if (!(await exists(filePath))) {
+ filePath = path.join(root, 'index.html');
+ }
+
+ const ext = path.extname(filePath);
+ res.setHeader('Content-Type', mime[ext] || 'application/octet-stream');
+ createReadStream(filePath).pipe(res);
+}
+
+const server = http.createServer((req, res) => {
+ serve(req, res).catch((error) => {
+ res.writeHead(500);
+ res.end(error?.stack || String(error));
+ });
+});
+
+server.listen(port, host, () => {
+ console.log(`web-ele dist server: http://${host}:${port}${basePath}/`);
+ console.log(`api proxy: ${apiPrefix} -> ${apiTarget}`);
+});