Ver código fonte

Merge branch 'main' into huahai_master

# Conflicts:
#	app.js
#	package.json
#	router/user.router.js
wanghao 1 dia atrás
pai
commit
88f9f7065b

+ 5 - 5
.vscode/settings.json

@@ -1,7 +1,7 @@
 {
-  "editor.defaultFormatter": "esbenp.prettier-vscode",
-  "[vue]": {
-    "editor.defaultFormatter": "esbenp.prettier-vscode"
-  },
-  "editor.formatOnSave": true
+  "editor.foldingImportsByDefault": true,
+  "editor.codeActionsOnSave": {
+    "source.organizeImports": "always",
+    "source.fixAll": "always"
+  }
 }

+ 10 - 9
app.js

@@ -72,15 +72,16 @@ app.use(
 app.use(
   koajwt({ secret: config.JWT_SECRET }).unless({
     path: [
-      /^\/api\/user\/ssoLogin/,
-      /^\/api\/user\/login/,
-      /^\/api\/user\/wechat/,
-      /^\/api\/user\/sendEmail/,
-      /^\/api\/user\/regist/,
-      /^\/api\/user\/password/,
-      /^\/api\/admin\/page\/detail/,
-      /^\/api\/ai\/proxy/,
-      /^\/api\/firefly/,
+      /^\/api\/editor\/user\/ssoLogin/,
+      /^\/api\/editor\/user\/login/,
+      /^\/api\/editor\/user\/admin\/login/,
+      /^\/api\/editor\/user\/wechat/,
+      /^\/api\/editor\/user\/sendEmail/,
+      /^\/api\/editor\/user\/regist/,
+      /^\/api\/editor\/user\/password/,
+      /^\/api\/editor\/admin\/page\/detail/,
+      /^\/api\/editor\/ai\/proxy/,
+      /^\/api\/editor\/firefly/,
     ],
   }),
 );

+ 1 - 3
config.default.js

@@ -73,14 +73,13 @@ const AI_KEY = '';
 const EMBEDDING = 'text-embedding-v3';
 const MODEL = 'qwen-plus';
 const DATABASE_URL = 'postgresql://';
-const ZHIPU_AI_KEY = '';
 
 /**
  * 模型配置
  * 此服务需付费使用(未付费开启会导致页面和项目创建报错)
  */
 // 模型服务调用地址
-const MODEL_BASE_URL = '';
+const MODEL_BASE_URL = 'http://api-model.marsview.com.cn';
 // 启用后端模型服务,
 const ENABLE_MODEL_SERVICE = true;
 
@@ -111,7 +110,6 @@ module.exports = {
   EMAIL_PASSWORD,
   WECHAT_APP_ID,
   WECHAT_APP_SECRET,
-  ZHIPU_AI_KEY,
   AI_BASE_URL,
   AI_KEY,
   EMBEDDING,

+ 2 - 1
controller/admin.js

@@ -52,8 +52,9 @@ async function getPageDetail(ctx) {
   }
 
   console.log('info', pageInfo);
+
   // 如果项目ID为空,则判断改页面是否公开或私有,私有页面需要登录才可访问,公开页面无需登录
-  if (pageInfo.isTemplate == 0 && !projectId && pageInfo.isPublic === 2) {
+  if (pageInfo.isTemplate == 0 && (!projectId || projectId === '0') && pageInfo.isPublic === 2) {
     const { userId } = util.decodeToken(ctx);
     // 需要判断用户是否是开发者或体验者;
     if (pageInfo.userId !== userId) {

+ 2 - 19
controller/ai.controller.js

@@ -1,7 +1,5 @@
-const aiService = require('../service/ai/ai.service.js');
 const util = require('../utils/util');
 const { model: openaiModel } = require('../service/ai/openai.service');
-const { findRelevantContent } = require('../service/ai/embedding.service');
 const { getSystemPrompt } = require('../service/ai/prompt.service');
 const { streamText } = require('ai');
 
@@ -21,21 +19,6 @@ function formatMessages(messages) {
 }
 
 module.exports = {
-  async codeGenerate(ctx) {
-    const { message } = ctx.request.body;
-    if (!message) {
-      return util.fail(ctx, '请输入提示词');
-    }
-    try {
-      const result = await aiService.ApiZhipuAi(message);
-      util.success(ctx, {
-        jsx: result[0],
-        config: result[1],
-      });
-    } catch (error) {
-      util.fail(ctx, error);
-    }
-  },
   async chatStream(ctx) {
     try {
       const { messages } = ctx.request.body;
@@ -50,8 +33,8 @@ module.exports = {
         : lastMessage.content;
 
       // 获取相关上下文
-      const relevantContent = await findRelevantContent(lastMessageContent);
-      const systemPrompt = getSystemPrompt(relevantContent.map((c) => c.content).join('\n'));
+      // const relevantContent = await findRelevantContent(lastMessageContent);
+      const systemPrompt = getSystemPrompt(lastMessageContent);
 
       const { textStream } = streamText({
         model: openaiModel,

+ 14 - 15
controller/pages.controller.js

@@ -153,22 +153,21 @@ module.exports = {
       // 开启模型服务后,需要复制模型
       if (ENABLE_MODEL_SERVICE) {
         // 获取项目模型列表
-        const res = await request
-          .post(
-            `${MODEL_BASE_URL}/api/model/copy`,
-            JSON.stringify({
-              oldProjectId: String(page.projectId),
-              newProjectId: String(projectId),
-            }),
-            {
-              headers: {
-                authorization: ctx.request.headers?.authorization,
-              },
+        const res = await request.post(
+          `${MODEL_BASE_URL}/api/model/model/copy`,
+          JSON.stringify({
+            oldProjectId: String(page.projectId),
+            newProjectId: String(projectId),
+          }),
+          {
+            headers: {
+              authorization: ctx.request.headers?.authorization,
             },
-          )
-          .catch((error) => {
-            ctx.throw(400, '模型创建失败:' + error);
-          });
+          },
+        );
+        if (res.status !== 200) {
+          return ctx.throw(400, '模型创建失败');
+        }
         const result = JSON.parse(res.data);
         const dictMap = result.oldNewDataDictionaryIdMap;
         page.pageData &&

+ 3 - 3
controller/projects.controller.js

@@ -9,7 +9,7 @@ const pageService = require('../service/pages.service');
 const publishService = require('../service/publish.service');
 const request = require('../utils/request');
 const util = require('../utils/util');
-const { MODEL_BASE_URL } = require('../config');
+const { MODEL_BASE_URL, ENABLE_MODEL_SERVICE } = require('../config');
 
 module.exports = {
   async getCategoryList(ctx) {
@@ -83,7 +83,7 @@ module.exports = {
         // 获取项目模型列表
         const res = await request
           .post(
-            `${MODEL_BASE_URL}/api/model/copy`,
+            `${MODEL_BASE_URL}/api/model/model/copy`,
             JSON.stringify({
               oldProjectId: String(project.id),
               newProjectId: String(insertRecord.insertId),
@@ -192,7 +192,7 @@ module.exports = {
     // 删除项目对应访问者权限
     await projectUserService.deleteUserByProjectId(id);
     // 删除模型表
-    await request.delete(`${MODEL_BASE_URL}/api/model/projectId/${id}`, {
+    await request.delete(`${MODEL_BASE_URL}/api/model/model/projectId/${id}`, {
       headers: {
         authorization: ctx.request.headers?.authorization,
       },

+ 4 - 2
package.json

@@ -49,6 +49,8 @@
   },
   "devDependencies": {
     "dotenv": "^16.4.7",
-    "eslint": "^8.56.0"
-  }
+    "eslint": "^8.56.0",
+    "prettier": "^3.5.3"
+  },
+  "packageManager": "pnpm@10.7.1+sha512.2d92c86b7928dc8284f53494fb4201f983da65f0fb4f0d40baafa5cf628fa31dae3e5968f12466f17df7e97310e30f343a648baea1b9b350685dafafffdf5808"
 }

+ 10 - 0
pnpm-lock.yaml

@@ -123,6 +123,9 @@ importers:
       eslint:
         specifier: ^8.56.0
         version: 8.57.1
+      prettier:
+        specifier: ^3.5.3
+        version: 3.5.3
 
 packages:
 
@@ -2259,6 +2262,11 @@ packages:
     resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
     engines: {node: '>= 0.8.0'}
 
+  prettier@3.5.3:
+    resolution: {integrity: sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==}
+    engines: {node: '>=14'}
+    hasBin: true
+
   process-nextick-args@2.0.1:
     resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==}
 
@@ -4412,6 +4420,8 @@ snapshots:
 
   prelude-ls@1.2.1: {}
 
+  prettier@3.5.3: {}
+
   process-nextick-args@2.0.1: {}
 
   process@0.11.10: {}

+ 1 - 1
router/admin.js

@@ -1,6 +1,6 @@
 const Router = require('@koa/router');
 const admin = require('../controller/admin');
-const router = new Router({ prefix: '/api/admin' });
+const router = new Router({ prefix: '/admin' });
 /**
  * 项目后台配置API接口
  */

+ 1 - 4
router/ai.router.js

@@ -1,6 +1,6 @@
 const Router = require('@koa/router');
 const ai = require('../controller/ai.controller');
-const router = new Router({ prefix: '/api/ai' });
+const router = new Router({ prefix: '/ai' });
 const request = require('../utils/request');
 const util = require('../utils/util');
 const qs = require('qs');
@@ -14,9 +14,6 @@ const { chatStream } = require('../controller/ai.controller');
 // 流式chat
 router.post('/stream', bodyParser(), chatStream);
 
-// 项目配置
-router.post('/lib/chat', ai.codeGenerate);
-
 // 接口转发(get)
 router.get('/proxy', async (ctx) => handleProxy(ctx, 'get'));
 

+ 1 - 1
router/dashboard.js

@@ -1,6 +1,6 @@
 const Router = require('@koa/router');
 const dashboard = require('../controller/dashboard.controller');
-const router = new Router({ prefix: '/api/dashboard' });
+const router = new Router({ prefix: '/dashboard' });
 /**
  * 项目后台配置API接口
  */

+ 1 - 1
router/img.cloud.js

@@ -1,6 +1,6 @@
 const Router = require('@koa/router');
 const fs = require('fs');
-const router = new Router({ prefix: '/api/cloud' });
+const router = new Router({ prefix: '/cloud' });
 const util = require('../utils/util');
 const sdk = require('@baiducloud/sdk');
 const Minio = require('minio');

+ 1 - 1
router/lib.router.js

@@ -1,5 +1,5 @@
 const Router = require('@koa/router');
-const router = new Router({ prefix: '/api/libs' });
+const router = new Router({ prefix: '/libs' });
 const libController = require('../controller/lib.controller');
 
 /**

+ 1 - 1
router/menu.router.js

@@ -1,6 +1,6 @@
 const Router = require('@koa/router');
 const menuController = require('../controller/menu.controller');
-const router = new Router({ prefix: '/api/project/menu' });
+const router = new Router({ prefix: '/project/menu' });
 
 /**
  * 菜单管理API接口

+ 1 - 1
router/mock.router.js

@@ -1,5 +1,5 @@
 const Router = require('@koa/router');
-const router = new Router({ prefix: '/api/firefly' });
+const router = new Router({ prefix: '/firefly' });
 const util = require('../utils/util');
 const fireflyService = require('../service/firefly.service');
 

+ 1 - 1
router/pages.router.js

@@ -1,5 +1,5 @@
 const Router = require('@koa/router');
-const router = new Router({ prefix: '/api/pages' });
+const router = new Router({ prefix: '/pages' });
 const pagesController = require('../controller/pages.controller');
 
 /**

+ 1 - 1
router/project.user.router.js

@@ -1,6 +1,6 @@
 const Router = require('@koa/router');
 const userController = require('../controller/project.user.controller');
-const router = new Router({ prefix: '/api/project/user' });
+const router = new Router({ prefix: '/project/user' });
 
 /**
  * 项目添加开发者服务API接口

+ 1 - 1
router/projects.router.js

@@ -1,5 +1,5 @@
 const Router = require('@koa/router');
-const router = new Router({ prefix: '/api/projects' });
+const router = new Router({ prefix: '/projects' });
 const projectsController = require('../controller/projects.controller');
 
 /**

+ 1 - 1
router/publish.router.js

@@ -1,5 +1,5 @@
 const Router = require('@koa/router');
-const router = new Router({ prefix: '/api/page/publish' });
+const router = new Router({ prefix: '/page/publish' });
 const publishController = require('../controller/publish.controller');
 
 /**

+ 1 - 1
router/robot.router.js

@@ -3,7 +3,7 @@ const lark = require('@larksuiteoapi/node-sdk');
 const config = require('../config');
 const request = require('../utils/request');
 const util = require('../utils/util');
-const router = new Router({ prefix: '/api/robot' });
+const router = new Router({ prefix: '/robot' });
 
 /**
  * 飞书机器人服务接口

+ 1 - 1
router/roles.router.js

@@ -1,6 +1,6 @@
 const Router = require('@koa/router');
 const rolesController = require('../controller/roles.controller');
-const router = new Router({ prefix: '/api/project/role' });
+const router = new Router({ prefix: '/project/role' });
 
 /**
  * 角色服务API接口

+ 1 - 1
router/templates.router.js

@@ -1,5 +1,5 @@
 const Router = require('@koa/router');
-const router = new Router({ prefix: '/api/templates' });
+const router = new Router({ prefix: '/templates' });
 const templates = require('../controller/templates.controller');
 
 /**

+ 65 - 2
router/user.router.js

@@ -1,5 +1,5 @@
 const Router = require('@koa/router');
-const router = new Router({ prefix: '/api/user' });
+const router = new Router({ prefix: '/user' });
 const util = require('../utils/util');
 const userService = require('../service/user.service');
 const projectService = require('../service/projects.service');
@@ -17,7 +17,7 @@ const request = require('../utils/request');
 const { Keyv } = require('keyv');
 const keyv = new Keyv();
 /**
- * 用户登录
+ * 编辑器端用户登录
  */
 router.post('/login', async (ctx) => {
   const { userName, userPwd, openId } = ctx.request.body;
@@ -39,6 +39,38 @@ router.post('/login', async (ctx) => {
     }
   }
 
+  const token = util.createToken({ userName, userId: res.id, nickName: res.nickName });
+  userService.updateUserInfo(res.id);
+  util.success(ctx, {
+    userId: res.id,
+    userName,
+    token,
+  });
+});
+
+/**
+ * admin端登录
+ */
+router.post('/admin/login', async (ctx) => {
+  const { userName, userPwd, openId } = ctx.request.body;
+  if (!userName || !userPwd) {
+    util.fail(ctx, '用户名或密码不能为空');
+    return;
+  }
+  const pwd = new md5().update(userPwd).digest('hex');
+  const res = await userService.findSubUser(userName, pwd, openId || userName);
+
+  if (!res) {
+    util.fail(ctx, '用户名或密码错误');
+    return;
+  }
+  if (!res.openId && openId) {
+    const cacheUser = await keyv.get(openId);
+    if (cacheUser) {
+      await userService.bindOpenId({ ...cacheUser, id: res.id });
+    }
+  }
+
   console.log("user res信息")
   console.log(res)
 
@@ -446,6 +478,37 @@ router.post('/subUser/delete', async (ctx) => {
   }
 });
 
+/**
+ * 平台管理员创建用户账号
+ */
+router.post('/create/account', async (ctx) => {
+  const { userName, userPwd } = ctx.request.body;
+  if (!userName || !userPwd) {
+    util.fail(ctx, '用户名或密码不能为空');
+    return;
+  }
+  const user = await userService.search(userName);
+  if (user) {
+    util.fail(ctx, '当前用户已存在');
+    return;
+  }
+
+  const nickName = userName.split('@')[0];
+  const pwd = new md5().update(userPwd).digest('hex');
+  const res = await userService.create(nickName, userName, pwd);
+  if (res.affectedRows == 1) {
+    const token = util.createToken({ userName, userId: res.insertId });
+
+    util.success(ctx, {
+      userId: res.id,
+      userName,
+      token,
+    });
+  } else {
+    util.fail(ctx, '创建失败,请稍后重试');
+  }
+});
+
 //addbywanghao  sso   20250512
 router.post('/ssoLogin', async (ctx) => {
   const { userIdno } = ctx.request.body;

+ 0 - 332
service/ai/ai.service.js

@@ -1,332 +0,0 @@
-const { ChatZhipuAI } = require('@langchain/community/chat_models/zhipuai');
-const { HumanMessage } = require('@langchain/core/messages');
-const { GlmModelProvider } = require('./provider/model/glm');
-const { RunnableConfig } = require('@langchain/core/runnables');
-const { extractCodeBlocks } = require('./provider/utils');
-const ZhipuAI = require('./provider/base/ZhipuAPIModel');
-const ZHIPU_AI_KEY = require('../../config').ZHIPU_AI_KEY;
-class AiService {
-  async buildGeneratePrompt({ message }) {
-    const codePrompt = `
-        You are a low-code component development expert.
-        Your task is to help me generate two files for a low-code development module: index.jsx and config.js.
-        The index.jsx file should define the structure of the component using React and Ant Design, and the config.js file should specify the component's property configurations.
-
-        Here’s an example of a login form component:
-
-        index.jsx file:
-        // jsx
-        export default ({ id, type, config, onClick, onDateChange,onTextChange }, ref) => {
-            const { useState } = window.React;
-            const {
-              Button,
-              Checkbox,
-              ColorPicker,
-              DatePicker,
-              Form,
-              Input,
-              InputNumber,
-              Radio,
-              Select,
-              Slider,
-              Switch,
-            } = window.antd;
-            const { RangePicker } = DatePicker;
-            const { TextArea } = Input;
-            const [dateFormat, setDateFormat] = useState(
-              config.props.dateFormat || 'YYYY-MM-DD HH:mm:ss'
-            );
-            const onDatePickerChange = (date, dateString) => {
-              onDateChange && onDateChange(date, dateString, dateFormat);
-            };
-            const onFinish = (values) => {
-              onClick && onClick(values);
-            };
-            return (
-              <div data-id={id} data-type={type}>
-                <Form
-                  labelCol={{ span: config.props.labelCol }}
-                  wrapperCol={{ span: config.props.wrapperCol }}
-                  layout={config.props.layout}
-                  style={{ maxWidth: config.props.maxWidth }}
-                  onFinish={onFinish}
-                >
-                  <Form.Item label="Checkbox" name="disabled" valuePropName="checked">
-                    <Checkbox>Checkbox</Checkbox>
-                  </Form.Item>
-                  <Form.Item label="Radio">
-                    <Radio.Group>
-                      <Radio value="apple"> Apple </Radio>
-                      <Radio value="pear"> Pear </Radio>
-                    </Radio.Group>
-                  </Form.Item>
-                  <Form.Item label="Input">
-                    <Input placeholder={config.props.textInput} />
-                  </Form.Item>
-                  <Form.Item label="Select">
-                    <Select>
-                      <Select.Option value="demo">Demo</Select.Option>
-                    </Select>
-                  </Form.Item>
-                  <Form.Item label="DataFormat" name="dateFormat">
-                    <Input
-                      value={dateFormat}
-                      onChange={(e) => setDateFormat(e.target.value)}
-                    />
-                  </Form.Item>
-                  <Form.Item label="DatePicker">
-                    <DatePicker onChange={onDatePickerChange} />
-                  </Form.Item>
-                  <Form.Item label="RangePicker">
-                    <RangePicker />
-                  </Form.Item>
-                  <Form.Item label="InputNumber">
-                    <InputNumber placeholder={config.props.numberInput} />
-                  </Form.Item>
-                  <Form.Item label="TextArea">
-                    <TextArea rows={config.props.textAreaRow} showCount={config.props.showCount}  onChange={onTextChange}/>
-                  </Form.Item>
-                  <Form.Item label="Switch" valuePropName="checked">
-                    <Switch />
-                  </Form.Item>
-                  <Form.Item label="Button" wrapperCol={{
-                      offset: config.props.offset,
-                      span: config.props.wrapperCol,
-                    }}>
-                    <Button block={config.props.block} type={config.props.btnType}>
-                      {config.props.loginBtn}
-                    </Button>
-                  </Form.Item>
-                  <Form.Item label="Slider">
-                    <Slider />
-                  </Form.Item>
-                  <Form.Item label="ColorPicker">
-                    <ColorPicker />
-                  </Form.Item>
-                </Form>
-              </div>
-            );
-          };
-
-
-          config.js file:
-          // config.js
-          export default {
-              // 组件属性配置JSON
-              attrs: [
-                {
-                  type: 'Title',
-                  label: '基础设置',
-                  key: 'basic',
-                },
-                {
-                  type: 'Select',
-                  label: '布局',
-                  name: ['layout'],
-                  props: {
-                    options: [
-                      { value: 'horizontal', label: 'horizontal' },
-                      { value: 'vertical', label: 'vertical' },
-                      { value: 'inline', label: 'inline' }
-                    ],
-                  },
-                },
-                {
-                  type: 'Select',
-                  label: '按钮类型',
-                  name: ['btnType'],
-                  props: {
-                    // options参数必须写完整
-                    options: [
-                      { value: 'primary', label: 'primary' },
-                      { value: 'default', label: 'default' },
-                      { value: 'ghost', label: 'ghost' },
-                      { value: 'dashed', label: 'dashed' },
-                      { value: 'text', label: 'text' },
-                      { value: 'link', label: 'link' },
-                    ],
-                  },
-                },
-                {
-                  type: 'InputNumber',
-                  label: 'labelCol',
-                  name: ['labelCol'],
-                },
-                {
-                  type: 'InputNumber',
-                  label: 'wrapperCol',
-                  name: ['wrapperCol'],
-                },
-                {
-                  type: 'InputNumber',
-                  label: 'offset',
-                  name: ['offset'],
-                },
-                {
-                  type: 'Input',
-                  label: '按钮名称',
-                  name: ['btnText'],
-                },
-                {
-                  type: 'Switch',
-                  label: '块状按钮',
-                  name: ['block'],
-                },
-                {
-                  type: 'Input',
-                  label: '初始文本',
-                  name: ['textInput'],
-                },
-                {
-                  type: 'InputNumber',
-                  label: '初始数值',
-                  name: ['numberInput'],
-                },
-                
-                {
-                  type: 'InputNumber',
-                  label: '文本框占据',
-                  name: ['textAreaRow'],
-                },
-                {
-                  type: 'Switch',
-                  label: '显示字符数',
-                  name: ['showCount'],
-                },
-              ],
-              config: {
-                // 组件默认属性值
-                props: {
-                  layout: 'horizontal',
-                  labelCol: 8,
-                  offset: 8,
-                  wrapperCol: 16,
-                  maxWidth: 500,
-                  btnType: 'primary',
-                  btnText: '按钮',
-                  textInput: '初始文本',
-                  numberInput: 12,
-                  textAreaRow: 4,
-                  showCount: true
-                },
-                style: {
-
-                },
-                events: [],
-              },
-              // 组件事件
-              events: [
-                {
-                  value: 'onClick',
-                  name: '表单提交事件',
-                },
-                {
-                  value: 'onDateChange',
-                  name: '日期时间变化事件',
-                },
-                {
-                  value: 'onTextChange',
-                  name: '文本输入事件'
-                }
-              ],
-              methods: [],
-            };   
-
-            Note: If you need to import hooks like useState and useEffect, you should import them using const { useState, useEffect } = window.React;. 
-            Similarly, Ant Design components should be imported in this way: const { Button, Form, DatePicker, Tag } = window.antd;.
-            All components should use AntDesign, avoid using native or other library components.
-            Now, based on the above structure and configuration, I need you to generate the index.jsx and config.js files for a new component. 
-            The description of this component in Chinese is #{message}. You can understand it in English and help me implement the code of the component
-            Please return only the code for both files, without any additional descirption text or markdown syntax.
-            Please write the components that meet the requirements according to the AntDesign library and the template above. Please don't try to omit the content, and be sure to return the code completely.
-        `;
-
-    const prompt = codePrompt.replace('#{message}', message);
-    return prompt;
-  }
-
-  async ApiZhipuAi(message) {
-    const prompt = await this.buildGeneratePrompt({ message });
-    const zhipuProvider = new ZhipuAI(ZHIPU_AI_KEY);
-    const params = {
-      model: 'glm-4-plus',
-      messages: [
-        {
-          role: 'user',
-          content: prompt,
-        },
-      ],
-      top_p: 0.7,
-      temperature: 0.9,
-      max_tokens: 1024,
-    };
-    try {
-      const response = await zhipuProvider.createCompletion(params);
-    } catch (error) {
-      console.error('API call failed:', error.message);
-    }
-  }
-
-  async codeGenerate(message) {
-    const modelProvider = new GlmModelProvider();
-
-    const aiRunnableAbortController = new AbortController();
-    const aiRunnable = await modelProvider.createRunnable({
-      signal: aiRunnableAbortController.signal,
-    });
-
-    const sessionId = `code_session_${Date.now()}`;
-
-    const aiRunnableConfig = {
-      configurable: {
-        sessionId,
-      },
-    };
-
-    const sessionIdHistoriesMap = await GlmModelProvider.sessionIdHistoriesMap;
-
-    const isSessionHistoryExists = !!sessionIdHistoriesMap[sessionId];
-
-    const prompt = await this.buildGeneratePrompt({ message });
-
-    const buildStream = async () => {
-      let aiStream = null;
-      if (!isSessionHistoryExists) {
-        delete sessionIdHistoriesMap[sessionId];
-        aiStream = aiRunnable.stream(
-          {
-            input: prompt,
-          },
-          aiRunnableConfig,
-        );
-      } else {
-        aiStream = aiRunnable.stream(
-          {
-            input: `
-                    continue, please do not reply with any text other than the code, and do not use markdown syntax.
-                    go continue.
-                  `,
-          },
-          aiRunnableConfig,
-        );
-      }
-      return aiStream;
-    };
-
-    let result = [];
-    const aiStream = await buildStream();
-    if (aiStream) {
-      for await (const chunk of aiStream) {
-        const text = GlmModelProvider.answerContentToText(chunk.content);
-        result.push(text);
-      }
-    }
-    const ai_stream_string = result.join('');
-    const code_array = extractCodeBlocks(ai_stream_string);
-    // 解析生成的代码
-
-    return [code_array[0], code_array[1]];
-  }
-}
-
-module.exports = new AiService();

+ 0 - 106
service/ai/provider/base/BaseModelProvider.js

@@ -1,106 +0,0 @@
-const { InMemoryChatMessageHistory } = require("@langchain/core/chat_history");
-const { BaseMessage, MessageContent } = require("@langchain/core/messages");
-const {
-  ChatPromptTemplate,
-  HumanMessagePromptTemplate,
-  MessagesPlaceholder,
-} = require("@langchain/core/prompts");
-const {
-  Runnable,
-  RunnableWithMessageHistory,
-} = require("@langchain/core/runnables");
-const { z } = require("zod");
-
-class BaseModelProvider {
-  static sessionIdHistoriesMap = {};
-
-  static answerContentToText(content) {
-    if (typeof content === "string") {
-      return content;
-    }
-
-    return content
-      .map((c) => {
-        if (c.type === "text") {
-          return c.text;
-        }
-        return "";
-      })
-      .join("");
-  }
-
-  async getModel() {
-    if (!this.model) {
-      this.model = await this.createModel();
-    }
-    return this.model;
-  }
-
-  createPrompt(options) {
-    const { useHistory = true } = options ?? {};
-    const prompt = ChatPromptTemplate.fromMessages(
-      [
-        useHistory ? new MessagesPlaceholder("history") : "",
-        HumanMessagePromptTemplate.fromTemplate("{input}"),
-      ].filter(Boolean)
-    );
-    return prompt;
-  }
-
-  async getHistory(sessionId, appendHistoryMessages) {
-    if (BaseModelProvider.sessionIdHistoriesMap[sessionId] === undefined) {
-      const messageHistory = new InMemoryChatMessageHistory();
-
-      if (appendHistoryMessages && appendHistoryMessages.length > 0) {
-        await messageHistory.addMessages(appendHistoryMessages);
-      }
-
-      BaseModelProvider.sessionIdHistoriesMap[sessionId] = messageHistory;
-    }
-    return BaseModelProvider.sessionIdHistoriesMap[sessionId];
-  }
-
-  createRunnableWithMessageHistory(chain, historyMessages) {
-    return new RunnableWithMessageHistory({
-      runnable: chain,
-      getMessageHistory: async (sessionId) =>
-        await this.getHistory(sessionId, historyMessages),
-      inputMessagesKey: "input",
-      historyMessagesKey: "history",
-    });
-  }
-
-  async createRunnable(options) {
-    const { useHistory = true, historyMessages = [], signal } = options ?? {};
-    const model = await this.getModel();
-    const prompt = await this.createPrompt({ useHistory });
-    const chain = prompt.pipe(signal ? model.bind({ signal }) : model);
-    return useHistory
-      ? await this.createRunnableWithMessageHistory(
-          chain,
-          historyMessages || []
-        )
-      : chain;
-  }
-
-  async createStructuredOutputRunnable(options) {
-    const {
-      useHistory = true,
-      historyMessages = [],
-      zodSchema,
-    } = options ?? {};
-    const model = await this.getModel();
-    const prompt = await this.createPrompt({ useHistory });
-    const chain = prompt.pipe(model);
-    return useHistory
-      ? await this.createRunnableWithMessageHistory(
-          chain,
-          historyMessages || []
-        )
-      : chain;
-  }
-}
-
-module.exports = {
-  BaseModelProvider,
-};

+ 0 - 38
service/ai/provider/base/ZhipuAPIModel.js

@@ -1,38 +0,0 @@
-const request = require("../../../../utils/request");
-const { generateToken } = require("../utils/zhiputoken");
-
-class ZhipuAI {
-    constructor(apiKey) {
-      if (!apiKey) {
-        throw new Error("API Key is required");
-      }
-      this.apiKey = apiKey;
-      this.cacheToken = true;
-      this.baseUrl = "https://open.bigmodel.cn/api/paas/v4/chat/completions";
-    }
-  
-    async createCompletion(params) {
-      if (!params.model) {
-        throw new Error("Model name is required");
-      }
-      if (!params.messages || !Array.isArray(params.messages)) {
-        throw new Error("Messages array is required");
-      }
-      const token = await generateToken(this.apiKey, this.cacheToken);
-      const headers = {
-        baseUrl: this.baseUrl,
-        Authorization: token,
-        timeout: 10000,
-      };
-  
-      try {
-        const response = await request.post(this.baseUrl, JSON.stringify(params), { headers });
-        return response.data;
-      } catch (error) {
-        console.error("Error calling ZhipuAI API:", error.response?.data || error.message);
-        throw error;
-      }
-    }
-  }
-
-module.exports = ZhipuAI;

+ 0 - 23
service/ai/provider/model/glm.js

@@ -1,23 +0,0 @@
-const { BaseModelProvider } = require('../base/BaseModelProvider');
-const { ChatZhipuAI } = require('@langchain/community/chat_models/zhipuai');
-const { ZHIPU_AI_KEY } = require('../../../../config');
-class GlmModelProvider extends BaseModelProvider {
-  async createModel() {
-    const aiKey = ZHIPU_AI_KEY;
-    const model_name = 'glm-4';
-
-    const model = new ChatZhipuAI({
-      apiKey: aiKey,
-      model: model_name,
-      temperature: 0.95, // never use 1.0, some models do not support it
-      maxRetries: 3,
-      verbose: true,
-    });
-
-    return model;
-  }
-}
-
-module.exports = {
-  GlmModelProvider,
-};

+ 0 - 17
service/ai/provider/utils/index.js

@@ -1,17 +0,0 @@
-const extractCodeBlocks = (str) => {
-  if (!str) {
-    return [];
-  }
-
-  // 正则表达式匹配所有的代码块内容
-  const matches = str.match(/```[\s\S]*?\n([\s\S]*?)\n```/g);
-
-  // 如果找到了匹配项,返回提取的内容,否则返回空数组
-  return matches
-    ? matches.map((match) =>
-        match.replace(/```[\s\S]*?\n([\s\S]*?)\n```/, "$1").trim()
-      )
-    : [];
-};
-
-module.exports = { extractCodeBlocks };

+ 0 - 40
service/ai/provider/utils/zhiputoken.js

@@ -1,40 +0,0 @@
-
-const jsonwebtoken = require("jsonwebtoken")
-
-const API_TOKEN_TTL_SECONDS = 3 * 60
-const CACHE_TTL_SECONDS = API_TOKEN_TTL_SECONDS - 30
-const tokenCache = {}
-const generateToken = (apiSecretKey, cache = true) => {
-
-    try {
-        if (tokenCache[apiSecretKey] && Date.now() - tokenCache[apiSecretKey].createAt < (CACHE_TTL_SECONDS * 1000)) {
-            return tokenCache[apiSecretKey].token
-        }
-
-        const [apiKey, secret] = apiSecretKey.split(".")
-        const payload = {
-            "api_key": apiKey,
-            "exp": Math.round(Date.now() * 1000) + API_TOKEN_TTL_SECONDS * 1000,
-            "timestamp": Math.round(Date.now() * 1000),
-        }
-        // algorithm = "HS256", headers = { "alg": "HS256", "sign_type": "SIGN" }
-        //@ts-ignore 不用管
-        const ret = jsonwebtoken.sign(payload, secret, {
-            algorithm: "HS256",
-            header: { alg: "HS256", sign_type: "SIGN" }
-        })
-        if (cache) {
-            tokenCache[apiSecretKey] = {
-                token: ret,
-                createAt: Date.now()
-            }
-        }
-        return ret
-    } catch (e) {
-        throw "invalid api_key"
-    }
-}
-
-module.exports = {
-    generateToken
-}

+ 1 - 1
service/dashboard.service.js

@@ -126,7 +126,7 @@ class DashboardService {
     const offset = (+pageNum - 1) * pageSize + '';
     const limit = pageSize;
     const statement = `SELECT id,nick_name nickName,user_name userName,avatar,created_at createdAt, updated_at updatedAt FROM users where ${
-      userId ? 'user_id = ' + userId : '1=1'
+      userId ? 'id = ' + userId : '1=1'
     } LIMIT ${offset},${limit};`;
     const [result] = await connection.execute(statement, []);
     return result;

+ 7 - 0
service/user.service.js

@@ -8,6 +8,13 @@ class UserService {
     const [result] = await connection.execute(statement, [userName, userPwd, openId]);
     return result[0];
   }
+  // 子用户登录
+  async findSubUser(userName, userPwd, openId) {
+    const statement =
+      'SELECT id, open_id as openId, user_name as userName, nick_name as nickName, avatar FROM users WHERE (user_name = ? and user_pwd = ?) or open_id = ? ;';
+    const [result] = await connection.execute(statement, [userName, userPwd, openId]);
+    return result[0];
+  }
   // 用户注册
   async create(nickName, userName, userPwd, parentId = null) {
     const statement = 'INSERT INTO users (nick_name, user_name, user_pwd, parent_id) VALUES (?, ?, ?, ?);';

+ 8 - 0
sql更新日志.md

@@ -33,3 +33,11 @@ ADD COLUMN `phone_number` INT(11) NULL COMMENT '手机号' AFTER `union_id`;
 ALTER TABLE `pages`
 ADD COLUMN `app_type` int(1) NULL DEFAULT 1 COMMENT '应用类型' AFTER `project_id`
 ;
+
+## 6.7 修改项目主题色默认值
+
+/_ 请确认以下 SQL 符合您的变更需求,务必确认无误后再提交执行 _/
+
+ALTER TABLE `projects`
+MODIFY COLUMN `system_theme_color` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '#1677ff' COMMENT '系统主题色' AFTER `footer`
+;

+ 8 - 3
utils/installer.js

@@ -1,5 +1,9 @@
 const fs = require('node:fs');
 const path = require('node:path');
+const Router = require('@koa/router');
+const apiRouter = new Router({
+  prefix: '/api/editor',
+});
 
 /**
  * 路由自动注册
@@ -12,11 +16,12 @@ const routerInstaller = (app) => {
   });
   const include = routers.filter((i) => exclude.indexOf(i) === -1);
   include.forEach((i) => {
-    app.use(require(`${routerdir}/${i}`).routes());
-    app.use(require(`${routerdir}/${i}`).allowedMethods());
+    apiRouter.use(require(`${routerdir}/${i}`).routes());
+    apiRouter.use(require(`${routerdir}/${i}`).allowedMethods());
   });
+  app.use(apiRouter.routes());
+  app.use(apiRouter.allowedMethods());
 };
-
 module.exports = {
   routerInstaller,
 };