gs-ai-assistant 1.0.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +115 -0
- package/dist/gs-ai-assistant.css +1 -0
- package/dist/gs-ai-assistant.js +714 -0
- package/dist/gs-ai-assistant.umd.cjs +1 -0
- package/dist/vite.svg +1 -0
- package/index.d.ts +1 -0
- package/package.json +43 -0
package/README.md
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
---
|
|
2
|
+
|
|
3
|
+
<h1 align="center">谷信软件科技有限公司</h1>
|
|
4
|
+
|
|
5
|
+
<p align="center">轻量、定制的现代化企业级前端框架</p>
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
### 介绍
|
|
10
|
+
|
|
11
|
+
这是一套**轻量、定制的现代化前端开发架构**,自 2023 年起从头开始构建,并在实践中不断迭代优化。最初的技术探索过程中,曾涉及低代码平台的研究,随着开发的深入,该架构逐步演化为公司前端项目的标准开发模式。
|
|
12
|
+
|
|
13
|
+
该架构基于 [Vue 3](https://cn.vuejs.org/guide/introduction)、[Ant Design Vue 4](https://www.antdv.com/components/overview-cn)和[Bootstrap 5](https://getbootstrap.com/docs/5.3/customize/optimize/),结合模块化设计思想,提供了一种 高效、灵活、可扩展 的前端开发方案。
|
|
14
|
+
|
|
15
|
+
## 核心特点
|
|
16
|
+
• 渐进式架构:采用 Vue 3 组合式 API,降低组件复杂度,提升代码复用性。
|
|
17
|
+
• 统一规范(UI):结合 Antdv 4 提供一致的设计语言,确保界面美观、交互流畅。
|
|
18
|
+
• 性能优化(CSS):基于 Bootstrap 5 现代化样式体系,提高样式复用性,减少兼容性适配成本,提升开发效率。
|
|
19
|
+
• 跨平台兼容:内置响应式布局,自适应平板和移动端,提供一致的用户体验。**基础布局支持,实际页面需要适配调整**
|
|
20
|
+
• 模块化设计:鼓励封装和复用,每个功能块作为独立模块,便于维护和扩展。
|
|
21
|
+
• 面向企业应用:专为公司内部系统和新项目定制,支持灵活配置,满足不同业务需求。
|
|
22
|
+
|
|
23
|
+
## 特性
|
|
24
|
+
|
|
25
|
+
- 快速组件
|
|
26
|
+
- 📖 提供 EList 组件和示例
|
|
27
|
+
- 📖 提供 ETree 组件和示例
|
|
28
|
+
- 📖 提供 ETable 组件和示例
|
|
29
|
+
- 📖 提供 ESelect 组件和示例
|
|
30
|
+
- Antdv4
|
|
31
|
+
- 🍭 支持 定制主题(全局)
|
|
32
|
+
- 🍭 支持 局部主题 (弃用 tailwindcss, 使用局部主题实现按钮换色)
|
|
33
|
+
- 🍭 支持 动态主题(低代码)
|
|
34
|
+
- 🍭 支持 深色模式
|
|
35
|
+
|
|
36
|
+
## **📌 快速组件**
|
|
37
|
+
| **组件** | **功能** |
|
|
38
|
+
|----------|-------------|
|
|
39
|
+
| **EList** | 卡片展示,支持 增/删/改/查 |
|
|
40
|
+
| **ETree** | 组织机构,支持 增/删/改/查 |
|
|
41
|
+
| **ETable** | 表格展示,支持 增/删/改/查 |
|
|
42
|
+
| **ESelect** | 组织机构选择,支持 联动/搜索/增/删/改/等 |
|
|
43
|
+
| **EModal** | 弹窗 |
|
|
44
|
+
| **EDrawer** | 侧窗 |
|
|
45
|
+
|
|
46
|
+
## **📌 结构说明**
|
|
47
|
+
- `EList`、`ETree`、`ETable`
|
|
48
|
+
- **统一使用 `CResponsiveHeader` 组件**,提供:
|
|
49
|
+
- `left` 插槽:用于头部左侧筛选 & 操作。
|
|
50
|
+
- `right` 插槽:用于头部右侧筛选 & 操作。
|
|
51
|
+
- `header` 插槽:头部自定义内容。
|
|
52
|
+
- `tag` 插槽:用于过滤器。
|
|
53
|
+
- `content` 插槽:用于展示补充内容。
|
|
54
|
+
- **`ESelect` 组件扩展**:支持 `dropdownRender`,可自定义下拉框内容。
|
|
55
|
+
|
|
56
|
+
## **📌 其他优化**
|
|
57
|
+
| **优化项** | **说明** |
|
|
58
|
+
|------------|----------|
|
|
59
|
+
| **数据库支持** | PostgreSQL、Oracle 适配尚未完成,老版本支持双数据库 |
|
|
60
|
+
| **长耗时导入** | 进度反馈 + 动态分页查询 (`dao.getListWithPagination`) |
|
|
61
|
+
| **图片支持** | SM4 加密(仅供参考) |
|
|
62
|
+
| **图片压缩** | 有点击压缩功能(仅供参考) |
|
|
63
|
+
| **WebSocket** | 支持实时数据交互 |
|
|
64
|
+
|
|
65
|
+
## 浏览器兼容性
|
|
66
|
+
|
|
67
|
+
支持所有符合 ES5 的浏览器(不支持 IE8 及以下版本)。
|
|
68
|
+
|
|
69
|
+
## 社区生态
|
|
70
|
+
|
|
71
|
+
由社区维护的项目如下:
|
|
72
|
+
|
|
73
|
+
| Project | Status | 描述 |
|
|
74
|
+
| --------------------- | ------------------------------------------------------------ | ------------------------------------------------------- |
|
|
75
|
+
| [ant-design-vue] | [![ant-design-vue-status]][ant-design-vue-package] | 基于 Ant Design 设计体系的 Vue 组件库 |
|
|
76
|
+
| [axios] | [![axios-status]][axios-package] | 基于 Promise 的 HTTP 客户端,用于浏览器和 Node.js |
|
|
77
|
+
| [core-js] | [![core-js-status]][core-js-package] | ECMAScript 规范的 polyfill,提供兼容性支持 |
|
|
78
|
+
| [nprogress] | [![nprogress-status]][nprogress-package] | 轻量级的页面加载进度条组件 |
|
|
79
|
+
| [qs] | [![qs-status]][qs-package] | 强大的查询字符串解析和序列化工具 |
|
|
80
|
+
| [vue] | [![vue-status]][vue-package] | 渐进式 JavaScript 框架,用于构建用户界面 |
|
|
81
|
+
| [vue-request] | [![vue-request-status]][vue-request-package] | 基于 Vue 3 的请求管理库,简化数据请求和状态管理 |
|
|
82
|
+
| [vue-router] | [![vue-router-status]][vue-router-package] | Vue.js 的官方路由库,支持单页面应用的路由管理 |
|
|
83
|
+
| [vuedraggable] | [![vuedraggable-status]][vuedraggable-package] | Vue 的拖拽排序组件,基于 Sortable.js |
|
|
84
|
+
| [vuex] | [![vuex-status]][vuex-package] | Vue.js 的状态管理模式,适用于大型应用 |
|
|
85
|
+
|
|
86
|
+
[ant-design-vue]: https://github.com/vueComponent/ant-design-vue
|
|
87
|
+
[axios]: https://github.com/axios/axios
|
|
88
|
+
[core-js]: https://github.com/zloirock/core-js
|
|
89
|
+
[nprogress]: https://github.com/rstacruz/nprogress
|
|
90
|
+
[qs]: https://github.com/ljharb/qs
|
|
91
|
+
[vue]: https://github.com/vuejs/core
|
|
92
|
+
[vue-request]: https://github.com/AttoJS/vue-request
|
|
93
|
+
[vue-router]: https://github.com/vuejs/vue-router
|
|
94
|
+
[vuedraggable]: https://github.com/SortableJS/Vue.Draggable
|
|
95
|
+
[vuex]: https://github.com/vuejs/vuex
|
|
96
|
+
[ant-design-vue-status]: https://img.shields.io/npm/v/ant-design-vue.svg
|
|
97
|
+
[axios-status]: https://img.shields.io/npm/v/axios.svg
|
|
98
|
+
[core-js-status]: https://img.shields.io/npm/v/core-js.svg
|
|
99
|
+
[nprogress-status]: https://img.shields.io/npm/v/nprogress.svg
|
|
100
|
+
[qs-status]: https://img.shields.io/npm/v/qs.svg
|
|
101
|
+
[vue-status]: https://img.shields.io/npm/v/vue.svg
|
|
102
|
+
[vue-request-status]: https://img.shields.io/npm/v/vue-request.svg
|
|
103
|
+
[vue-router-status]: https://img.shields.io/npm/v/vue-router.svg
|
|
104
|
+
[vuedraggable-status]: https://img.shields.io/npm/v/vuedraggable.svg
|
|
105
|
+
[vuex-status]: https://img.shields.io/npm/v/vuex.svg
|
|
106
|
+
[ant-design-vue-package]: https://npmjs.com/package/ant-design-vue
|
|
107
|
+
[axios-package]: https://npmjs.com/package/axios
|
|
108
|
+
[core-js-package]: https://npmjs.com/package/core-js
|
|
109
|
+
[nprogress-package]: https://npmjs.com/package/nprogress
|
|
110
|
+
[qs-package]: https://npmjs.com/package/qs
|
|
111
|
+
[vue-package]: https://npmjs.com/package/vue
|
|
112
|
+
[vue-request-package]: https://npmjs.com/package/vue-request
|
|
113
|
+
[vue-router-package]: https://npmjs.com/package/vue-router
|
|
114
|
+
[vuedraggable-package]: https://npmjs.com/package/vuedraggable
|
|
115
|
+
[vuex-package]: https://npmjs.com/package/vuex
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.ai-chat-sidebar[data-v-ff65b680]{width:248px;flex:0 0 248px;background:#f5f6f8}.ai-sidebar-nav[data-v-ff65b680]{padding-bottom:22px}.ai-sidebar-nav-item[data-v-ff65b680],.ai-session-item[data-v-ff65b680]{width:100%;border:0;color:#24272d;background:transparent;text-align:left;transition:background-color .2s ease,color .2s ease,transform .2s ease}.ai-sidebar-nav-item[data-v-ff65b680]{display:flex;align-items:center;gap:12px;min-height:42px;padding:0 14px;border-radius:14px;font-size:15px;font-weight:500}.ai-sidebar-nav-item[data-v-ff65b680]:hover,.ai-session-item[data-v-ff65b680]:hover{background:#fff}.ai-sidebar-nav-item[data-v-ff65b680]:active,.ai-session-item[data-v-ff65b680]:active{transform:scale(.98)}.ai-sidebar-nav-item.active[data-v-ff65b680],.ai-session-item.active[data-v-ff65b680]{background:#fff;color:#1677ff;box-shadow:0 8px 20px #0f172a0f}.ai-sidebar-section-title[data-v-ff65b680]{color:#7b818d;font-size:13px;font-weight:600}.ai-session-item[data-v-ff65b680]{min-height:38px;padding:0 8px 0 14px;border-radius:12px;font-size:14px;cursor:pointer}.ai-session-delete[data-v-ff65b680]{width:24px;height:24px;border-radius:8px;color:#9aa1ad;opacity:0;transition:opacity .2s ease,background-color .2s ease,color .2s ease}.ai-session-item:hover .ai-session-delete[data-v-ff65b680]{opacity:1}.ai-session-delete[data-v-ff65b680]:hover{color:#cf1322!important;background:#fff1f0}.ai-session-collapse[data-v-ff65b680]{min-height:0}.ai-session-collapse[data-v-ff65b680] .ant-collapse-header{align-items:center!important;padding:0 14px 8px!important}.ai-session-collapse[data-v-ff65b680] .ant-collapse-content-box{padding:0!important}.ai-instruction-card[data-v-85d5df68]{min-height:112px;border:1px solid #edf0f5;transition:border-color .2s ease,box-shadow .2s ease}.ai-instruction-card[data-v-85d5df68]:hover{border-color:#1677ff;box-shadow:0 8px 24px #0f172a14}.ai-message-bubble[data-v-de55b932]{max-width:78%;line-height:1.75;font-size:14px}.ai-pre-wrap[data-v-de55b932]{white-space:pre-wrap;word-break:break-word}.ai-chat-messages[data-v-8bae25ad]{min-height:220px;padding:20px 24px 24px}.ai-message-bubble[data-v-8bae25ad]{max-width:78%;line-height:1.75;font-size:14px}.ai-pre-wrap[data-v-8bae25ad]{white-space:pre-wrap;word-break:break-word}.ai-thinking-collapse[data-v-8bae25ad]{margin-bottom:8px;color:#6b7280}.ai-thinking-collapse[data-v-8bae25ad] .ant-collapse-header{display:inline-flex!important;align-items:center!important;gap:6px;padding:0!important;color:#6b7280!important;font-size:13px}.ai-thinking-collapse[data-v-8bae25ad] .ant-collapse-content-box{padding:8px 0 0 16px!important;border-left:2px solid #e5e7eb}.ai-thinking-content[data-v-8bae25ad]{margin:0;white-space:pre-wrap;word-break:break-word;color:#6b7280;font-family:inherit;line-height:1.65}.ai-input-box[data-v-e63f761d]{border:1px solid #dfe3ea;border-radius:18px;box-shadow:0 10px 28px #0f172a14}.ai-input-box[data-v-e63f761d] textarea.ant-input{width:100%;border:none;box-shadow:none;resize:none;padding:0;font-size:14px}.ai-model-select[data-v-e63f761d]{width:160px}.ai-action-type-select[data-v-e63f761d]{width:96px}.ai-send-btn[data-v-e63f761d]{flex:0 0 auto}.ai-chat-wrap[data-v-0a4b31b9]{height:70vh;min-height:460px;max-height:760px}.floating-ai[data-v-83236aae]{position:fixed;pointer-events:auto;touch-action:none;-webkit-user-select:none;user-select:none}.tool-btn[data-v-83236aae]{box-shadow:0 6px 20px #00000026}.ai-btn[data-v-83236aae]{width:58px;height:132px;border:none;border-radius:30px;background:#fff;color:#b30000;display:inline-flex;flex-direction:column;align-items:center;justify-content:center;gap:8px;padding:0}.ai-mark[data-v-83236aae]{font-size:20px;line-height:1;font-weight:700;color:#5b7cff;font-style:italic}.ai-label[data-v-83236aae]{font-size:20px;line-height:1;font-weight:600;color:#b30000;writing-mode:vertical-rl;text-orientation:upright;letter-spacing:1px}.ai-btn[data-v-83236aae]:hover,.ai-btn[data-v-83236aae]:focus{color:#b30000;background:#fff}.ai-btn[data-v-83236aae]:active{background:#f8f9ff}
|
|
@@ -0,0 +1,714 @@
|
|
|
1
|
+
import { onMounted as pe, nextTick as ve, getCurrentInstance as oe, watch as Q, getCurrentScope as ye, hasInjectionContext as me, inject as T, shallowRef as U, computed as A, toValue as Y, watchEffect as be, unref as K, ref as p, resolveComponent as $, createElementBlock as w, openBlock as d, createElementVNode as v, createVNode as M, normalizeClass as Z, withCtx as L, createBlock as F, createCommentVNode as O, Fragment as P, renderList as B, toDisplayString as S, withModifiers as fe, createTextVNode as ae, withKeys as we, isRef as ce, provide as J, normalizeStyle as xe } from "vue";
|
|
2
|
+
import { useStore as ee } from "vuex";
|
|
3
|
+
const te = /* @__PURE__ */ new WeakMap(), ke = /* @__NO_SIDE_EFFECTS__ */ (...e) => {
|
|
4
|
+
var t;
|
|
5
|
+
const s = e[0], o = (t = oe()) === null || t === void 0 ? void 0 : t.proxy, n = o ?? ye();
|
|
6
|
+
if (n == null && !me()) throw new Error("injectLocal must be called in setup");
|
|
7
|
+
return n && te.has(n) && s in te.get(n) ? te.get(n)[s] : T(...e);
|
|
8
|
+
}, Ae = typeof window < "u" && typeof document < "u";
|
|
9
|
+
typeof WorkerGlobalScope < "u" && globalThis instanceof WorkerGlobalScope;
|
|
10
|
+
const Se = Object.prototype.toString, Ie = (e) => Se.call(e) === "[object Object]";
|
|
11
|
+
function ue(e) {
|
|
12
|
+
return e.endsWith("rem") ? Number.parseFloat(e) * 16 : Number.parseFloat(e);
|
|
13
|
+
}
|
|
14
|
+
function se(e) {
|
|
15
|
+
return Array.isArray(e) ? e : [e];
|
|
16
|
+
}
|
|
17
|
+
function Me(e) {
|
|
18
|
+
return oe();
|
|
19
|
+
}
|
|
20
|
+
function Ce(e, t = !0, s) {
|
|
21
|
+
Me() ? pe(e, s) : t ? e() : ve(e);
|
|
22
|
+
}
|
|
23
|
+
function $e(e, t, s) {
|
|
24
|
+
return Q(e, t, {
|
|
25
|
+
...s,
|
|
26
|
+
immediate: !0
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
const le = Ae ? window : void 0;
|
|
30
|
+
function Te(e) {
|
|
31
|
+
var t;
|
|
32
|
+
const s = Y(e);
|
|
33
|
+
return (t = s?.$el) !== null && t !== void 0 ? t : s;
|
|
34
|
+
}
|
|
35
|
+
function ne(...e) {
|
|
36
|
+
const t = (o, n, c, a) => (o.addEventListener(n, c, a), () => o.removeEventListener(n, c, a)), s = A(() => {
|
|
37
|
+
const o = se(Y(e[0])).filter((n) => n != null);
|
|
38
|
+
return o.every((n) => typeof n != "string") ? o : void 0;
|
|
39
|
+
});
|
|
40
|
+
return $e(() => {
|
|
41
|
+
var o, n;
|
|
42
|
+
return [
|
|
43
|
+
(o = (n = s.value) === null || n === void 0 ? void 0 : n.map((c) => Te(c))) !== null && o !== void 0 ? o : [le].filter((c) => c != null),
|
|
44
|
+
se(Y(s.value ? e[1] : e[0])),
|
|
45
|
+
se(K(s.value ? e[2] : e[1])),
|
|
46
|
+
Y(s.value ? e[3] : e[2])
|
|
47
|
+
];
|
|
48
|
+
}, ([o, n, c, a], l, g) => {
|
|
49
|
+
if (!o?.length || !n?.length || !c?.length) return;
|
|
50
|
+
const f = Ie(a) ? { ...a } : a, m = o.flatMap((i) => n.flatMap((k) => c.map((h) => t(i, k, h, f))));
|
|
51
|
+
g(() => {
|
|
52
|
+
m.forEach((i) => i());
|
|
53
|
+
});
|
|
54
|
+
}, { flush: "post" });
|
|
55
|
+
}
|
|
56
|
+
// @__NO_SIDE_EFFECTS__
|
|
57
|
+
function Le() {
|
|
58
|
+
const e = U(!1), t = oe();
|
|
59
|
+
return t && pe(() => {
|
|
60
|
+
e.value = !0;
|
|
61
|
+
}, t), e;
|
|
62
|
+
}
|
|
63
|
+
// @__NO_SIDE_EFFECTS__
|
|
64
|
+
function Ve(e) {
|
|
65
|
+
const t = /* @__PURE__ */ Le();
|
|
66
|
+
return A(() => (t.value, !!e()));
|
|
67
|
+
}
|
|
68
|
+
const We = Symbol("vueuse-ssr-width");
|
|
69
|
+
// @__NO_SIDE_EFFECTS__
|
|
70
|
+
function Ee() {
|
|
71
|
+
const e = me() ? /* @__PURE__ */ ke(We, null) : null;
|
|
72
|
+
return typeof e == "number" ? e : void 0;
|
|
73
|
+
}
|
|
74
|
+
function Ne(e, t = {}) {
|
|
75
|
+
const { window: s = le, ssrWidth: o = /* @__PURE__ */ Ee() } = t, n = /* @__PURE__ */ Ve(() => s && "matchMedia" in s && typeof s.matchMedia == "function"), c = U(typeof o == "number"), a = U(), l = U(!1), g = (f) => {
|
|
76
|
+
l.value = f.matches;
|
|
77
|
+
};
|
|
78
|
+
return be(() => {
|
|
79
|
+
if (c.value) {
|
|
80
|
+
c.value = !n.value, l.value = Y(e).split(",").some((f) => {
|
|
81
|
+
const m = f.includes("not all"), i = f.match(/\(\s*min-width:\s*(-?\d+(?:\.\d*)?[a-z]+\s*)\)/), k = f.match(/\(\s*max-width:\s*(-?\d+(?:\.\d*)?[a-z]+\s*)\)/);
|
|
82
|
+
let h = !!(i || k);
|
|
83
|
+
return i && h && (h = o >= ue(i[1])), k && h && (h = o <= ue(k[1])), m ? !h : h;
|
|
84
|
+
});
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
n.value && (a.value = s.matchMedia(Y(e)), l.value = a.value.matches);
|
|
88
|
+
}), ne(a, "change", g, { passive: !0 }), A(() => l.value);
|
|
89
|
+
}
|
|
90
|
+
// @__NO_SIDE_EFFECTS__
|
|
91
|
+
function Oe(e = {}) {
|
|
92
|
+
const { window: t = le, initialWidth: s = Number.POSITIVE_INFINITY, initialHeight: o = Number.POSITIVE_INFINITY, listenOrientation: n = !0, includeScrollbar: c = !0, type: a = "inner" } = e, l = U(s), g = U(o), f = () => {
|
|
93
|
+
if (t) if (a === "outer")
|
|
94
|
+
l.value = t.outerWidth, g.value = t.outerHeight;
|
|
95
|
+
else if (a === "visual" && t.visualViewport) {
|
|
96
|
+
const { width: i, height: k, scale: h } = t.visualViewport;
|
|
97
|
+
l.value = Math.round(i * h), g.value = Math.round(k * h);
|
|
98
|
+
} else c ? (l.value = t.innerWidth, g.value = t.innerHeight) : (l.value = t.document.documentElement.clientWidth, g.value = t.document.documentElement.clientHeight);
|
|
99
|
+
};
|
|
100
|
+
f(), Ce(f);
|
|
101
|
+
const m = { passive: !0 };
|
|
102
|
+
return ne("resize", f, m), t && a === "visual" && t.visualViewport && ne(t.visualViewport, "resize", f, m), n && Q(Ne("(orientation: portrait)"), () => f()), {
|
|
103
|
+
width: l,
|
|
104
|
+
height: g
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
const z = (e, t) => {
|
|
108
|
+
const s = e.__vccOpts || e;
|
|
109
|
+
for (const [o, n] of t)
|
|
110
|
+
s[o] = n;
|
|
111
|
+
return s;
|
|
112
|
+
}, qe = { class: "ai-chat-sidebar border-end p-3 d-flex flex-column" }, Fe = { class: "ai-sidebar-nav d-flex flex-column gap-1" }, Re = { class: "ai-sidebar-section-title d-flex align-items-center gap-2" }, De = { class: "d-flex flex-column gap-2" }, je = ["onClick"], Ke = { class: "text-truncate flex-fill" }, Pe = {
|
|
113
|
+
__name: "AiAssistantSidebar",
|
|
114
|
+
setup(e) {
|
|
115
|
+
const t = T("aiCurrentView", p("draft")), s = T("aiSessions", p([])), o = T("aiActiveSessionId", p("")), n = T("aiInputMessage", p("")), c = p(["recent"]), a = A(() => [...s.value].sort((m, i) => i.updatedAt - m.updatedAt)), l = () => {
|
|
116
|
+
t.value = "draft", n.value = "";
|
|
117
|
+
}, g = (m) => {
|
|
118
|
+
o.value = m, t.value = "chat";
|
|
119
|
+
}, f = (m) => {
|
|
120
|
+
s.value = s.value.filter((i) => i.id !== m), o.value === m && (o.value = "", t.value = "draft", n.value = "");
|
|
121
|
+
};
|
|
122
|
+
return (m, i) => {
|
|
123
|
+
const k = $("a-icon"), h = $("a-empty"), x = $("a-button"), V = $("a-collapse-panel"), b = $("a-collapse");
|
|
124
|
+
return d(), w("aside", qe, [
|
|
125
|
+
v("div", Fe, [
|
|
126
|
+
v("button", {
|
|
127
|
+
class: Z(["ai-sidebar-nav-item", { active: K(t) === "draft" }]),
|
|
128
|
+
onClick: l
|
|
129
|
+
}, [
|
|
130
|
+
M(k, { type: "icon-edit" }),
|
|
131
|
+
i[2] || (i[2] = v("span", null, "新对话", -1))
|
|
132
|
+
], 2),
|
|
133
|
+
v("button", {
|
|
134
|
+
class: Z(["ai-sidebar-nav-item", { active: K(t) === "library" }]),
|
|
135
|
+
onClick: i[0] || (i[0] = (I) => t.value = "library")
|
|
136
|
+
}, [
|
|
137
|
+
M(k, { type: "icon-appstore" }),
|
|
138
|
+
i[3] || (i[3] = v("span", null, "AI 指令库", -1))
|
|
139
|
+
], 2)
|
|
140
|
+
]),
|
|
141
|
+
M(b, {
|
|
142
|
+
activeKey: c.value,
|
|
143
|
+
"onUpdate:activeKey": i[1] || (i[1] = (I) => c.value = I),
|
|
144
|
+
ghost: "",
|
|
145
|
+
class: "ai-session-collapse flex-fill overflow-auto"
|
|
146
|
+
}, {
|
|
147
|
+
default: L(() => [
|
|
148
|
+
M(V, { key: "recent" }, {
|
|
149
|
+
header: L(() => [
|
|
150
|
+
v("div", Re, [
|
|
151
|
+
M(k, { type: "icon-history" }),
|
|
152
|
+
i[4] || (i[4] = v("span", null, "最近会话", -1))
|
|
153
|
+
])
|
|
154
|
+
]),
|
|
155
|
+
default: L(() => [
|
|
156
|
+
v("div", De, [
|
|
157
|
+
a.value.length === 0 ? (d(), F(h, {
|
|
158
|
+
key: 0,
|
|
159
|
+
description: "暂无会话"
|
|
160
|
+
})) : O("", !0),
|
|
161
|
+
(d(!0), w(P, null, B(a.value, (I) => (d(), w("div", {
|
|
162
|
+
key: I.id,
|
|
163
|
+
class: Z(["ai-session-item d-flex align-items-center gap-2", { active: K(t) === "chat" && I.id === K(o) }]),
|
|
164
|
+
onClick: (W) => g(I.id)
|
|
165
|
+
}, [
|
|
166
|
+
v("span", Ke, S(I.title), 1),
|
|
167
|
+
M(x, {
|
|
168
|
+
type: "text",
|
|
169
|
+
size: "small",
|
|
170
|
+
class: "ai-session-delete",
|
|
171
|
+
onClick: fe((W) => f(I.id), ["stop"])
|
|
172
|
+
}, {
|
|
173
|
+
default: L(() => [
|
|
174
|
+
M(k, { type: "icon-delete" })
|
|
175
|
+
]),
|
|
176
|
+
_: 1
|
|
177
|
+
}, 8, ["onClick"])
|
|
178
|
+
], 10, je))), 128))
|
|
179
|
+
])
|
|
180
|
+
]),
|
|
181
|
+
_: 1
|
|
182
|
+
})
|
|
183
|
+
]),
|
|
184
|
+
_: 1
|
|
185
|
+
}, 8, ["activeKey"])
|
|
186
|
+
]);
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
}, ze = /* @__PURE__ */ z(Pe, [["__scopeId", "data-v-ff65b680"]]), He = { class: "ai-instruction-library flex-fill overflow-auto bg-white p-4" }, Ue = { class: "row g-3 mt-2" }, Ye = ["onClick"], Be = { class: "fw-semibold mb-2" }, Qe = { class: "small text-muted" }, Xe = {
|
|
190
|
+
__name: "AiInstructionLibrary",
|
|
191
|
+
setup(e) {
|
|
192
|
+
const t = ee(), s = p(""), o = T("aiInputMessage", p("")), n = T("aiActionType", p("chat")), c = T("aiCurrentView", p("draft")), a = A(() => t.state.app.aiAssistantConfig || {}), l = A(() => {
|
|
193
|
+
const m = a.value.instructions;
|
|
194
|
+
return Array.isArray(m) ? m : [];
|
|
195
|
+
}), g = A(() => {
|
|
196
|
+
const m = l.value || [], i = m.find((k) => k.label === s.value) || m[0];
|
|
197
|
+
return Array.isArray(i?.items) ? i.items : [];
|
|
198
|
+
}), f = (m) => {
|
|
199
|
+
o.value = m.prompt || "", n.value = m.actionType || "chat", c.value = "draft";
|
|
200
|
+
};
|
|
201
|
+
return Q(l, (m = []) => {
|
|
202
|
+
m.some((i) => i.label === s.value) || (s.value = m[0]?.label || "");
|
|
203
|
+
}, { immediate: !0 }), (m, i) => {
|
|
204
|
+
const k = $("a-tab-pane"), h = $("a-tabs");
|
|
205
|
+
return d(), w("div", He, [
|
|
206
|
+
i[1] || (i[1] = v("div", { class: "text-center mb-4" }, [
|
|
207
|
+
v("h3", { class: "mb-2" }, "AI 指令库"),
|
|
208
|
+
v("div", { class: "text-muted" }, "选择一个指令模板,快速开始当前系统的 AI 任务")
|
|
209
|
+
], -1)),
|
|
210
|
+
M(h, {
|
|
211
|
+
activeKey: s.value,
|
|
212
|
+
"onUpdate:activeKey": i[0] || (i[0] = (x) => s.value = x),
|
|
213
|
+
centered: ""
|
|
214
|
+
}, {
|
|
215
|
+
default: L(() => [
|
|
216
|
+
(d(!0), w(P, null, B(l.value, (x) => (d(), F(k, {
|
|
217
|
+
key: x.label,
|
|
218
|
+
tab: x.label
|
|
219
|
+
}, null, 8, ["tab"]))), 128))
|
|
220
|
+
]),
|
|
221
|
+
_: 1
|
|
222
|
+
}, 8, ["activeKey"]),
|
|
223
|
+
v("div", Ue, [
|
|
224
|
+
(d(!0), w(P, null, B(g.value, (x) => (d(), w("div", {
|
|
225
|
+
key: x.prompt,
|
|
226
|
+
class: "col-6 col-xl-4"
|
|
227
|
+
}, [
|
|
228
|
+
v("button", {
|
|
229
|
+
class: "ai-instruction-card w-100 h-100 text-start bg-white rounded p-3",
|
|
230
|
+
onClick: (V) => f(x)
|
|
231
|
+
}, [
|
|
232
|
+
v("div", Be, S(x.title), 1),
|
|
233
|
+
v("div", Qe, S(x.description), 1)
|
|
234
|
+
], 8, Ye)
|
|
235
|
+
]))), 128))
|
|
236
|
+
])
|
|
237
|
+
]);
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
}, Ge = /* @__PURE__ */ z(Xe, [["__scopeId", "data-v-85d5df68"]]), Je = { class: "ai-message-bubble bg-light rounded p-3" }, Ze = { class: "fw-semibold mb-2" }, et = {
|
|
241
|
+
key: 0,
|
|
242
|
+
class: "mb-2"
|
|
243
|
+
}, tt = {
|
|
244
|
+
key: 1,
|
|
245
|
+
class: "small text-muted mb-2"
|
|
246
|
+
}, st = { class: "ai-pre-wrap mb-0" }, at = {
|
|
247
|
+
__name: "AiTableResultMessage",
|
|
248
|
+
props: {
|
|
249
|
+
message: {
|
|
250
|
+
type: Object,
|
|
251
|
+
required: !0
|
|
252
|
+
}
|
|
253
|
+
},
|
|
254
|
+
setup(e) {
|
|
255
|
+
const t = e, s = A(() => (Array.isArray(t.message.columns) ? t.message.columns : []).map((a) => {
|
|
256
|
+
const l = typeof a == "string" ? a : a.key || a.dataIndex || a.title;
|
|
257
|
+
return {
|
|
258
|
+
title: typeof a == "string" ? a : a.title || l,
|
|
259
|
+
dataIndex: typeof a == "string" ? a : a.dataIndex || l,
|
|
260
|
+
key: l
|
|
261
|
+
};
|
|
262
|
+
})), o = A(() => (Array.isArray(t.message.rows) ? t.message.rows : []).map((a, l) => ({
|
|
263
|
+
key: l,
|
|
264
|
+
...a
|
|
265
|
+
}))), n = A(() => JSON.stringify({
|
|
266
|
+
columns: t.message.columns,
|
|
267
|
+
rows: t.message.rows
|
|
268
|
+
}, null, 2));
|
|
269
|
+
return (c, a) => {
|
|
270
|
+
const l = $("a-table");
|
|
271
|
+
return d(), w("div", Je, [
|
|
272
|
+
v("div", Ze, S(e.message.title || "表格结果"), 1),
|
|
273
|
+
e.message.summary ? (d(), w("div", et, S(e.message.summary), 1)) : O("", !0),
|
|
274
|
+
e.message.sql ? (d(), w("div", tt, "SQL:" + S(e.message.sql), 1)) : O("", !0),
|
|
275
|
+
M(l, {
|
|
276
|
+
class: "mb-3",
|
|
277
|
+
size: "small",
|
|
278
|
+
bordered: "",
|
|
279
|
+
columns: s.value,
|
|
280
|
+
"data-source": o.value,
|
|
281
|
+
pagination: !1,
|
|
282
|
+
scroll: { x: !0 }
|
|
283
|
+
}, null, 8, ["columns", "data-source"]),
|
|
284
|
+
v("pre", st, S(n.value), 1)
|
|
285
|
+
]);
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
}, nt = /* @__PURE__ */ z(at, [["__scopeId", "data-v-de55b932"]]), ot = { class: "small text-muted mb-2" }, lt = {
|
|
289
|
+
key: 0,
|
|
290
|
+
class: "ai-message-bubble bg-light rounded p-3"
|
|
291
|
+
}, it = { class: "ai-pre-wrap text-warning-emphasis mb-3" }, rt = {
|
|
292
|
+
key: 1,
|
|
293
|
+
class: "ai-message-bubble bg-warning-subtle rounded p-3"
|
|
294
|
+
}, ct = { class: "ai-pre-wrap text-warning-emphasis mb-0" }, ut = {
|
|
295
|
+
key: 3,
|
|
296
|
+
class: "ai-message-bubble bg-light rounded p-3"
|
|
297
|
+
}, dt = { class: "fw-semibold mb-2" }, pt = {
|
|
298
|
+
key: 0,
|
|
299
|
+
class: "mb-2"
|
|
300
|
+
}, vt = { class: "small text-muted mb-2" }, mt = { key: 0 }, ft = { key: 1 }, _t = {
|
|
301
|
+
key: 1,
|
|
302
|
+
class: "small text-muted mb-2"
|
|
303
|
+
}, gt = { class: "ai-pre-wrap mb-0" }, ht = {
|
|
304
|
+
key: 4,
|
|
305
|
+
class: "ai-message-bubble bg-transparent p-0"
|
|
306
|
+
}, yt = { class: "ai-thinking-content" }, bt = { class: "ai-thinking-content" }, wt = {
|
|
307
|
+
key: 0,
|
|
308
|
+
class: "h-100 d-flex align-items-center justify-content-center text-muted"
|
|
309
|
+
}, xt = {
|
|
310
|
+
__name: "AiChatMessages",
|
|
311
|
+
setup(e) {
|
|
312
|
+
const t = ee(), s = T("aiSessions", p([])), o = T("aiActiveSessionId", p("")), n = T("aiCurrentView", p("draft")), c = A(() => t.state.app.aiAssistantConfig || {}), a = A(() => c.value.title || "AI 小助手"), l = A(() => c.value.welcomeMessage || ""), g = p(), f = A(() => {
|
|
313
|
+
if (n.value === "draft") return [];
|
|
314
|
+
const b = s.value.find((I) => I.id === o.value);
|
|
315
|
+
return Array.isArray(b?.messages) ? b.messages : [];
|
|
316
|
+
});
|
|
317
|
+
Q([o, () => f.value.length], async () => {
|
|
318
|
+
await ve(), g.value.scrollTop = g.value.scrollHeight;
|
|
319
|
+
});
|
|
320
|
+
const m = (b = {}) => (Array.isArray(b.columns) ? b.columns : []).map((W) => ({
|
|
321
|
+
title: W,
|
|
322
|
+
dataIndex: W,
|
|
323
|
+
key: W
|
|
324
|
+
})), i = (b = {}) => (Array.isArray(b.rows) ? b.rows : []).map((W, R) => ({
|
|
325
|
+
key: R,
|
|
326
|
+
...W
|
|
327
|
+
})), k = (b) => `Thinking ${b || 8}s`, h = (b) => JSON.stringify(b.data || [], null, 2), x = (b) => Array.isArray(b) ? b.join("、") : b, V = (b) => b.role === "user" ? "bg-primary-subtle text-dark p-3" : b.type === "error" ? "bg-danger-subtle text-danger border border-danger-subtle p-3" : b.role === "assistant" ? "bg-transparent p-0" : "bg-light p-3";
|
|
328
|
+
return (b, I) => {
|
|
329
|
+
const W = $("a-table"), R = $("a-collapse-panel"), j = $("a-collapse");
|
|
330
|
+
return d(), w("div", {
|
|
331
|
+
ref_key: "messageWrapRef",
|
|
332
|
+
ref: g,
|
|
333
|
+
class: "ai-chat-messages flex-fill overflow-auto bg-white"
|
|
334
|
+
}, [
|
|
335
|
+
(d(!0), w(P, null, B(f.value, (_, X) => (d(), w("div", {
|
|
336
|
+
key: X,
|
|
337
|
+
class: Z(["d-flex flex-column mb-4", [
|
|
338
|
+
_.role === "user" ? "align-items-end" : "align-items-start",
|
|
339
|
+
_.type
|
|
340
|
+
]])
|
|
341
|
+
}, [
|
|
342
|
+
v("div", ot, S(_.role === "user" ? "我" : a.value), 1),
|
|
343
|
+
_.type === "sql_result" ? (d(), w("div", lt, [
|
|
344
|
+
I[0] || (I[0] = v("div", { class: "fw-semibold mb-2" }, "执行 SQL:", -1)),
|
|
345
|
+
v("pre", it, S(_.sql), 1),
|
|
346
|
+
M(W, {
|
|
347
|
+
size: "small",
|
|
348
|
+
bordered: "",
|
|
349
|
+
columns: m(_.result),
|
|
350
|
+
"data-source": i(_.result),
|
|
351
|
+
pagination: !1,
|
|
352
|
+
scroll: { x: !0 }
|
|
353
|
+
}, null, 8, ["columns", "data-source"])
|
|
354
|
+
])) : _.type === "sql_preview" ? (d(), w("div", rt, [
|
|
355
|
+
I[1] || (I[1] = v("div", { class: "fw-semibold mb-2" }, "SQL 预览:", -1)),
|
|
356
|
+
v("pre", ct, S(_.content), 1)
|
|
357
|
+
])) : _.type === "table_result" ? (d(), F(nt, {
|
|
358
|
+
key: 2,
|
|
359
|
+
message: _
|
|
360
|
+
}, null, 8, ["message"])) : _.type === "chart_result" ? (d(), w("div", ut, [
|
|
361
|
+
v("div", dt, S(_.title || "图表结果"), 1),
|
|
362
|
+
_.summary ? (d(), w("div", pt, S(_.summary), 1)) : O("", !0),
|
|
363
|
+
v("div", vt, [
|
|
364
|
+
ae(" 图表类型:" + S(_.chartType || "未指定") + " ", 1),
|
|
365
|
+
_.xField ? (d(), w("span", mt, "|X 轴:" + S(_.xField), 1)) : O("", !0),
|
|
366
|
+
_.yFields ? (d(), w("span", ft, "|指标:" + S(x(_.yFields)), 1)) : O("", !0)
|
|
367
|
+
]),
|
|
368
|
+
_.sql ? (d(), w("div", _t, "SQL:" + S(_.sql), 1)) : O("", !0),
|
|
369
|
+
v("pre", gt, S(h(_)), 1)
|
|
370
|
+
])) : _.type === "thinking" ? (d(), w("div", ht, [
|
|
371
|
+
M(j, {
|
|
372
|
+
ghost: "",
|
|
373
|
+
class: "ai-thinking-collapse"
|
|
374
|
+
}, {
|
|
375
|
+
default: L(() => [
|
|
376
|
+
M(R, {
|
|
377
|
+
key: "thinking",
|
|
378
|
+
header: k(_.thinkingSeconds)
|
|
379
|
+
}, {
|
|
380
|
+
default: L(() => [
|
|
381
|
+
v("pre", yt, S(_.content), 1)
|
|
382
|
+
]),
|
|
383
|
+
_: 2
|
|
384
|
+
}, 1032, ["header"])
|
|
385
|
+
]),
|
|
386
|
+
_: 2
|
|
387
|
+
}, 1024)
|
|
388
|
+
])) : (d(), w("div", {
|
|
389
|
+
key: 5,
|
|
390
|
+
class: Z(["ai-message-bubble ai-pre-wrap rounded", V(_)])
|
|
391
|
+
}, [
|
|
392
|
+
_.thinking ? (d(), F(j, {
|
|
393
|
+
key: 0,
|
|
394
|
+
ghost: "",
|
|
395
|
+
class: "ai-thinking-collapse"
|
|
396
|
+
}, {
|
|
397
|
+
default: L(() => [
|
|
398
|
+
M(R, {
|
|
399
|
+
key: "thinking",
|
|
400
|
+
header: k(_.thinkingSeconds)
|
|
401
|
+
}, {
|
|
402
|
+
default: L(() => [
|
|
403
|
+
v("pre", bt, S(_.thinking), 1)
|
|
404
|
+
]),
|
|
405
|
+
_: 2
|
|
406
|
+
}, 1032, ["header"])
|
|
407
|
+
]),
|
|
408
|
+
_: 2
|
|
409
|
+
}, 1024)) : O("", !0),
|
|
410
|
+
v("div", null, S(_.content), 1)
|
|
411
|
+
], 2))
|
|
412
|
+
], 2))), 128)),
|
|
413
|
+
f.value.length === 0 ? (d(), w("div", wt, S(l.value || "开始一个新的 AI 对话"), 1)) : O("", !0)
|
|
414
|
+
], 512);
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
}, kt = /* @__PURE__ */ z(xt, [["__scopeId", "data-v-8bae25ad"]]), At = { class: "border-top px-4 py-3" }, St = { class: "ai-input-box d-flex flex-column gap-3 p-3 bg-white" }, It = { class: "d-flex align-items-center justify-content-between gap-3 w-100" }, Mt = { class: "d-flex align-items-center gap-2 min-w-0" }, Ct = {
|
|
418
|
+
key: 0,
|
|
419
|
+
class: "small text-muted text-nowrap"
|
|
420
|
+
}, $t = { class: "d-flex align-items-center gap-2" }, Tt = {
|
|
421
|
+
__name: "AiChatInput",
|
|
422
|
+
setup(e) {
|
|
423
|
+
const t = ee(), s = T("aiSessions", p([])), o = T("aiActiveSessionId", p("")), n = T("aiCurrentView", p("draft")), c = T("aiInputMessage", p("")), a = T("aiActionType", p("chat")), l = p(!1), g = p(""), f = A(() => t.state.app.aiAssistantConfig), m = A(() => f.value.title || "AI 小助手"), i = A(() => f.value.chatUrl), k = [
|
|
424
|
+
{ label: "聊天", value: "chat" },
|
|
425
|
+
{ label: "SQL", value: "sql" },
|
|
426
|
+
{ label: "表格", value: "table" },
|
|
427
|
+
{ label: "图表", value: "chart" }
|
|
428
|
+
], h = A(() => f.value.models.map((u) => {
|
|
429
|
+
const y = u.source || u.model_source || f.value.defaultModelSource || "online";
|
|
430
|
+
return {
|
|
431
|
+
...u,
|
|
432
|
+
source: y,
|
|
433
|
+
key: `${y}::${u.value}`
|
|
434
|
+
};
|
|
435
|
+
})), V = p((() => {
|
|
436
|
+
const u = f.value.defaultModelSource || "online", y = f.value.defaultModel;
|
|
437
|
+
return h.value.find((r) => r.source === u && r.value === y).key;
|
|
438
|
+
})()), b = A(() => h.value.find((u) => u.key === V.value)), I = A(() => n.value === "draft" ? "" : s.value.find((y) => y.id === o.value).debugLine), W = () => "s_" + Date.now().toString(36) + "_" + Math.random().toString(36).slice(2, 8), R = () => ({
|
|
439
|
+
id: W(),
|
|
440
|
+
title: "新对话",
|
|
441
|
+
messages: [],
|
|
442
|
+
debugLine: "",
|
|
443
|
+
updatedAt: Date.now()
|
|
444
|
+
}), j = () => s.value.find((u) => u.id === o.value), _ = () => {
|
|
445
|
+
const u = R();
|
|
446
|
+
return s.value.unshift(u), o.value = u.id, n.value = "chat", j();
|
|
447
|
+
}, X = (u, y) => {
|
|
448
|
+
u.messages.push({ role: "user", content: y }), u.title === "新对话" && (u.title = y), u.updatedAt = Date.now();
|
|
449
|
+
}, C = (u, y) => {
|
|
450
|
+
u.messages.push({ role: "assistant", content: y }), u.updatedAt = Date.now();
|
|
451
|
+
}, q = (u, y, E) => {
|
|
452
|
+
for (const r of y)
|
|
453
|
+
r.type === "ai" && r.content ? u.messages.push({
|
|
454
|
+
role: "assistant",
|
|
455
|
+
type: "ai",
|
|
456
|
+
content: r.content,
|
|
457
|
+
thinking: r.thinking,
|
|
458
|
+
thinkingSeconds: E
|
|
459
|
+
}) : ["thinking", "thought", "reasoning"].includes(r.type) && r.content ? u.messages.push({ role: "assistant", type: "thinking", content: r.content, thinkingSeconds: E }) : r.type === "sql_preview" && r.content ? u.messages.push({ role: "assistant", type: "sql_preview", content: r.content }) : r.type === "sql_result" ? u.messages.push({
|
|
460
|
+
role: "assistant",
|
|
461
|
+
type: "sql_result",
|
|
462
|
+
sql: r.sql,
|
|
463
|
+
result: r.result
|
|
464
|
+
}) : r.type === "table_result" ? u.messages.push({
|
|
465
|
+
role: "assistant",
|
|
466
|
+
type: "table_result",
|
|
467
|
+
title: r.title,
|
|
468
|
+
sql: r.sql,
|
|
469
|
+
columns: r.columns,
|
|
470
|
+
rows: r.rows,
|
|
471
|
+
summary: r.summary
|
|
472
|
+
}) : r.type === "chart_result" ? u.messages.push({
|
|
473
|
+
role: "assistant",
|
|
474
|
+
type: "chart_result",
|
|
475
|
+
title: r.title,
|
|
476
|
+
sql: r.sql,
|
|
477
|
+
chartType: r.chart_type,
|
|
478
|
+
xField: r.x_field,
|
|
479
|
+
yFields: r.y_fields,
|
|
480
|
+
data: r.data,
|
|
481
|
+
summary: r.summary
|
|
482
|
+
}) : r.type === "error" && r.content && u.messages.push({ role: "assistant", type: "error", content: r.content });
|
|
483
|
+
u.updatedAt = Date.now();
|
|
484
|
+
}, H = async () => {
|
|
485
|
+
const u = c.value.trim();
|
|
486
|
+
if (!u || l.value) return;
|
|
487
|
+
const y = n.value === "draft" ? _() : j();
|
|
488
|
+
X(y, u), c.value = "", g.value = "", l.value = !0;
|
|
489
|
+
try {
|
|
490
|
+
const E = await fetch("http://localhost:5011" + i.value, {
|
|
491
|
+
method: "POST",
|
|
492
|
+
headers: { "Content-Type": "application/json" },
|
|
493
|
+
body: JSON.stringify({
|
|
494
|
+
message: u,
|
|
495
|
+
session_id: y.id,
|
|
496
|
+
// 后端接口读取 action_type,前端内部变量仍用 actionType 对应配置字段。
|
|
497
|
+
action_type: a.value,
|
|
498
|
+
// 后端按 model_source + model 切换实际模型。
|
|
499
|
+
model_source: b.value.source,
|
|
500
|
+
model: b.value.value
|
|
501
|
+
})
|
|
502
|
+
});
|
|
503
|
+
if (!E.ok)
|
|
504
|
+
throw new Error(`HTTP ${E.status}`);
|
|
505
|
+
const r = await E.json();
|
|
506
|
+
y.debugLine = _e(r);
|
|
507
|
+
const G = r.steps || [];
|
|
508
|
+
if (G.length > 0) {
|
|
509
|
+
q(y, G, ie(r));
|
|
510
|
+
return;
|
|
511
|
+
}
|
|
512
|
+
C(y, r.reply);
|
|
513
|
+
} catch (E) {
|
|
514
|
+
g.value = `请求失败:${E.message}`;
|
|
515
|
+
} finally {
|
|
516
|
+
l.value = !1;
|
|
517
|
+
}
|
|
518
|
+
}, ie = (u) => Math.max(1, Math.round(u.usage.eval_count / 8)), _e = (u) => {
|
|
519
|
+
const y = u.usage, E = u.debug, r = `${(y.context_usage_ratio * 100).toFixed(1)}%`;
|
|
520
|
+
return `上下文:${y.prompt_eval_count} / ${y.context_limit}(${r})|回复:${y.eval_count}|历史:${E.history_message_count}`;
|
|
521
|
+
};
|
|
522
|
+
return (u, y) => {
|
|
523
|
+
const E = $("a-alert"), r = $("a-textarea"), G = $("a-select-option"), re = $("a-select"), ge = $("a-icon"), he = $("a-button");
|
|
524
|
+
return d(), w("div", At, [
|
|
525
|
+
g.value ? (d(), F(E, {
|
|
526
|
+
key: 0,
|
|
527
|
+
class: "mb-3",
|
|
528
|
+
message: g.value,
|
|
529
|
+
type: "error",
|
|
530
|
+
"show-icon": ""
|
|
531
|
+
}, null, 8, ["message"])) : O("", !0),
|
|
532
|
+
v("div", St, [
|
|
533
|
+
M(r, {
|
|
534
|
+
value: K(c),
|
|
535
|
+
"onUpdate:value": y[0] || (y[0] = (N) => ce(c) ? c.value = N : null),
|
|
536
|
+
placeholder: `给 ${m.value} 发送消息`,
|
|
537
|
+
"auto-size": { minRows: 2, maxRows: 5 },
|
|
538
|
+
onKeydown: we(fe(H, ["exact", "prevent"]), ["enter"])
|
|
539
|
+
}, null, 8, ["value", "placeholder", "onKeydown"]),
|
|
540
|
+
v("div", It, [
|
|
541
|
+
v("div", Mt, [
|
|
542
|
+
M(re, {
|
|
543
|
+
value: K(a),
|
|
544
|
+
"onUpdate:value": y[1] || (y[1] = (N) => ce(a) ? a.value = N : null),
|
|
545
|
+
size: "small",
|
|
546
|
+
class: "ai-action-type-select"
|
|
547
|
+
}, {
|
|
548
|
+
default: L(() => [
|
|
549
|
+
(d(), w(P, null, B(k, (N) => M(G, {
|
|
550
|
+
key: N.value,
|
|
551
|
+
value: N.value
|
|
552
|
+
}, {
|
|
553
|
+
default: L(() => [
|
|
554
|
+
ae(S(N.label), 1)
|
|
555
|
+
]),
|
|
556
|
+
_: 2
|
|
557
|
+
}, 1032, ["value"])), 64))
|
|
558
|
+
]),
|
|
559
|
+
_: 1
|
|
560
|
+
}, 8, ["value"]),
|
|
561
|
+
I.value ? (d(), w("span", Ct, S(I.value), 1)) : O("", !0)
|
|
562
|
+
]),
|
|
563
|
+
v("div", $t, [
|
|
564
|
+
M(re, {
|
|
565
|
+
value: V.value,
|
|
566
|
+
"onUpdate:value": y[2] || (y[2] = (N) => V.value = N),
|
|
567
|
+
size: "small",
|
|
568
|
+
class: "ai-model-select"
|
|
569
|
+
}, {
|
|
570
|
+
default: L(() => [
|
|
571
|
+
(d(!0), w(P, null, B(h.value, (N) => (d(), F(G, {
|
|
572
|
+
key: N.key,
|
|
573
|
+
value: N.key
|
|
574
|
+
}, {
|
|
575
|
+
default: L(() => [
|
|
576
|
+
ae(S(N.label), 1)
|
|
577
|
+
]),
|
|
578
|
+
_: 2
|
|
579
|
+
}, 1032, ["value"]))), 128))
|
|
580
|
+
]),
|
|
581
|
+
_: 1
|
|
582
|
+
}, 8, ["value"]),
|
|
583
|
+
M(he, {
|
|
584
|
+
type: "primary",
|
|
585
|
+
shape: "circle",
|
|
586
|
+
class: "ai-send-btn",
|
|
587
|
+
loading: l.value,
|
|
588
|
+
onClick: H
|
|
589
|
+
}, {
|
|
590
|
+
default: L(() => [
|
|
591
|
+
l.value ? O("", !0) : (d(), F(ge, {
|
|
592
|
+
key: 0,
|
|
593
|
+
type: "icon-send"
|
|
594
|
+
}))
|
|
595
|
+
]),
|
|
596
|
+
_: 1
|
|
597
|
+
}, 8, ["loading"])
|
|
598
|
+
])
|
|
599
|
+
])
|
|
600
|
+
])
|
|
601
|
+
]);
|
|
602
|
+
};
|
|
603
|
+
}
|
|
604
|
+
}, Lt = /* @__PURE__ */ z(Tt, [["__scopeId", "data-v-e63f761d"]]), Vt = { class: "ai-chat-wrap flex-fill d-flex bg-white" }, Wt = { class: "flex-fill d-flex flex-column min-w-0" }, Et = {
|
|
605
|
+
__name: "AiAssistantModal",
|
|
606
|
+
props: {
|
|
607
|
+
open: {
|
|
608
|
+
type: Boolean,
|
|
609
|
+
default: !1
|
|
610
|
+
}
|
|
611
|
+
},
|
|
612
|
+
emits: ["close"],
|
|
613
|
+
setup(e, { emit: t }) {
|
|
614
|
+
const s = t, o = ee(), n = A(() => o.state.app.aiAssistantConfig || {}), c = A(() => n.value.title || "AI 小助手"), a = A(() => `gs-eant-comp:ai-assistant:${c.value}`), l = p([]), g = p(""), f = p("draft"), m = p(""), i = p("chat");
|
|
615
|
+
return (() => {
|
|
616
|
+
try {
|
|
617
|
+
const h = localStorage.getItem(a.value);
|
|
618
|
+
if (!h) return;
|
|
619
|
+
const x = JSON.parse(h);
|
|
620
|
+
Array.isArray(x.sessions) && (l.value = x.sessions), x.activeSessionId && (g.value = x.activeSessionId), g.value && l.value.some((V) => V.id === g.value) && (f.value = "chat");
|
|
621
|
+
} catch (h) {
|
|
622
|
+
console.warn("[gs-eant-comp] AI assistant storage parse failed:", h);
|
|
623
|
+
}
|
|
624
|
+
})(), Q([l, g], () => {
|
|
625
|
+
localStorage.setItem(a.value, JSON.stringify({
|
|
626
|
+
activeSessionId: g.value,
|
|
627
|
+
sessions: l.value
|
|
628
|
+
}));
|
|
629
|
+
}, { deep: !0 }), J("aiSessions", l), J("aiActiveSessionId", g), J("aiCurrentView", f), J("aiInputMessage", m), J("aiActionType", i), (h, x) => {
|
|
630
|
+
const V = $("a-modal");
|
|
631
|
+
return d(), F(V, {
|
|
632
|
+
open: e.open,
|
|
633
|
+
title: c.value,
|
|
634
|
+
width: "76vw",
|
|
635
|
+
footer: null,
|
|
636
|
+
"mask-closable": !0,
|
|
637
|
+
"body-style": { padding: 0 },
|
|
638
|
+
"wrap-class-name": "vh-90",
|
|
639
|
+
onCancel: x[0] || (x[0] = (b) => s("close"))
|
|
640
|
+
}, {
|
|
641
|
+
default: L(() => [
|
|
642
|
+
v("div", Vt, [
|
|
643
|
+
M(ze),
|
|
644
|
+
v("main", Wt, [
|
|
645
|
+
f.value === "library" ? (d(), F(Ge, { key: 0 })) : (d(), w(P, { key: 1 }, [
|
|
646
|
+
M(kt),
|
|
647
|
+
M(Lt)
|
|
648
|
+
], 64))
|
|
649
|
+
])
|
|
650
|
+
])
|
|
651
|
+
]),
|
|
652
|
+
_: 1
|
|
653
|
+
}, 8, ["open", "title"]);
|
|
654
|
+
};
|
|
655
|
+
}
|
|
656
|
+
}, Nt = /* @__PURE__ */ z(Et, [["__scopeId", "data-v-0a4b31b9"]]), de = 58, Ot = 132, D = 16, qt = {
|
|
657
|
+
__name: "AiAssistantTool",
|
|
658
|
+
setup(e) {
|
|
659
|
+
const t = ee(), s = p(!1), o = p(null), n = p(!1), c = p(null), a = p(!1), l = p(0), g = p(0), f = p(0), m = p(0), { width: i, height: k } = /* @__PURE__ */ Oe(), h = p(Math.max(D, window.innerWidth - de - 24)), x = p(Math.max(D, Math.round(window.innerHeight * 0.7))), V = (C, q, H) => Math.min(Math.max(C, q), H), b = () => {
|
|
660
|
+
const C = Math.max(D, i.value - de - D), q = Math.max(D, k.value - Ot - D);
|
|
661
|
+
h.value = V(h.value, D, C), x.value = V(x.value, D, q);
|
|
662
|
+
}, I = (C) => {
|
|
663
|
+
!a.value || c.value !== C.pointerId || (h.value = f.value + C.clientX - l.value, x.value = m.value + C.clientY - g.value, b());
|
|
664
|
+
}, W = (C) => {
|
|
665
|
+
if (c.value !== C.pointerId) return;
|
|
666
|
+
(Math.abs(C.clientX - l.value) > 3 || Math.abs(C.clientY - g.value) > 3) && (n.value = !0, window.setTimeout(() => {
|
|
667
|
+
n.value = !1;
|
|
668
|
+
}, 0)), a.value = !1, c.value = null, window.removeEventListener("pointermove", I), window.removeEventListener("pointerup", W);
|
|
669
|
+
}, R = (C) => {
|
|
670
|
+
C.button === 0 && (c.value = C.pointerId, a.value = !0, l.value = C.clientX, g.value = C.clientY, f.value = h.value, m.value = x.value, window.addEventListener("pointermove", I), window.addEventListener("pointerup", W));
|
|
671
|
+
}, j = () => {
|
|
672
|
+
n.value || (s.value = !0);
|
|
673
|
+
};
|
|
674
|
+
Q([i, k], b, { immediate: !0 });
|
|
675
|
+
const _ = A(() => !!t.state.app.aiAssistantConfig?.enabled), X = A(() => ({
|
|
676
|
+
left: `${h.value}px`,
|
|
677
|
+
top: `${x.value}px`
|
|
678
|
+
}));
|
|
679
|
+
return (C, q) => {
|
|
680
|
+
const H = $("a-button");
|
|
681
|
+
return _.value ? (d(), w("div", {
|
|
682
|
+
key: 0,
|
|
683
|
+
ref_key: "aiFloatingRef",
|
|
684
|
+
ref: o,
|
|
685
|
+
class: "floating-ai",
|
|
686
|
+
style: xe(X.value),
|
|
687
|
+
onPointerdown: R
|
|
688
|
+
}, [
|
|
689
|
+
M(H, {
|
|
690
|
+
class: "tool-btn ai-btn",
|
|
691
|
+
onClick: j
|
|
692
|
+
}, {
|
|
693
|
+
default: L(() => [...q[1] || (q[1] = [
|
|
694
|
+
v("span", { class: "ai-mark" }, "Ai", -1),
|
|
695
|
+
v("span", { class: "ai-label" }, "小助手", -1)
|
|
696
|
+
])]),
|
|
697
|
+
_: 1
|
|
698
|
+
}),
|
|
699
|
+
M(Nt, {
|
|
700
|
+
open: s.value,
|
|
701
|
+
onClose: q[0] || (q[0] = (ie) => s.value = !1)
|
|
702
|
+
}, null, 8, ["open"])
|
|
703
|
+
], 36)) : O("", !0);
|
|
704
|
+
};
|
|
705
|
+
}
|
|
706
|
+
}, Ft = /* @__PURE__ */ z(qt, [["__scopeId", "data-v-83236aae"]]), Rt = (e) => {
|
|
707
|
+
e.component("AiAssistantTool", Ft);
|
|
708
|
+
}, Kt = {
|
|
709
|
+
install: Rt
|
|
710
|
+
};
|
|
711
|
+
export {
|
|
712
|
+
Ft as AiAssistantTool,
|
|
713
|
+
Kt as default
|
|
714
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
(function(E,e){typeof exports=="object"&&typeof module<"u"?e(exports,require("vue"),require("vuex")):typeof define=="function"&&define.amd?define(["exports","vue","vuex"],e):(E=typeof globalThis<"u"?globalThis:E||self,e(E.GsAiAssistant={},E.Vue,E.Vuex))})(this,(function(E,e,D){"use strict";const F=new WeakMap,U=(...t)=>{var n;const s=t[0],l=(n=e.getCurrentInstance())===null||n===void 0?void 0:n.proxy,a=l??e.getCurrentScope();if(a==null&&!e.hasInjectionContext())throw new Error("injectLocal must be called in setup");return a&&F.has(a)&&s in F.get(a)?F.get(a)[s]:e.inject(...t)},Y=typeof window<"u"&&typeof document<"u";typeof WorkerGlobalScope<"u"&&globalThis instanceof WorkerGlobalScope;const G=Object.prototype.toString,Q=t=>G.call(t)==="[object Object]";function q(t){return t.endsWith("rem")?Number.parseFloat(t)*16:Number.parseFloat(t)}function R(t){return Array.isArray(t)?t:[t]}function X(t){return e.getCurrentInstance()}function J(t,n=!0,s){X()?e.onMounted(t,s):n?t():e.nextTick(t)}function Z(t,n,s){return e.watch(t,n,{...s,immediate:!0})}const W=Y?window:void 0;function v(t){var n;const s=e.toValue(t);return(n=s?.$el)!==null&&n!==void 0?n:s}function O(...t){const n=(l,a,d,o)=>(l.addEventListener(a,d,o),()=>l.removeEventListener(a,d,o)),s=e.computed(()=>{const l=R(e.toValue(t[0])).filter(a=>a!=null);return l.every(a=>typeof a!="string")?l:void 0});return Z(()=>{var l,a;return[(l=(a=s.value)===null||a===void 0?void 0:a.map(d=>v(d)))!==null&&l!==void 0?l:[W].filter(d=>d!=null),R(e.toValue(s.value?t[1]:t[0])),R(e.unref(s.value?t[2]:t[1])),e.toValue(s.value?t[3]:t[2])]},([l,a,d,o],i,_)=>{if(!l?.length||!a?.length||!d?.length)return;const u=Q(o)?{...o}:o,m=l.flatMap(r=>a.flatMap(k=>d.map(g=>n(r,k,g,u))));_(()=>{m.forEach(r=>r())})},{flush:"post"})}function ee(){const t=e.shallowRef(!1),n=e.getCurrentInstance();return n&&e.onMounted(()=>{t.value=!0},n),t}function te(t){const n=ee();return e.computed(()=>(n.value,!!t()))}const ne=Symbol("vueuse-ssr-width");function se(){const t=e.hasInjectionContext()?U(ne,null):null;return typeof t=="number"?t:void 0}function oe(t,n={}){const{window:s=W,ssrWidth:l=se()}=n,a=te(()=>s&&"matchMedia"in s&&typeof s.matchMedia=="function"),d=e.shallowRef(typeof l=="number"),o=e.shallowRef(),i=e.shallowRef(!1),_=u=>{i.value=u.matches};return e.watchEffect(()=>{if(d.value){d.value=!a.value,i.value=e.toValue(t).split(",").some(u=>{const m=u.includes("not all"),r=u.match(/\(\s*min-width:\s*(-?\d+(?:\.\d*)?[a-z]+\s*)\)/),k=u.match(/\(\s*max-width:\s*(-?\d+(?:\.\d*)?[a-z]+\s*)\)/);let g=!!(r||k);return r&&g&&(g=l>=q(r[1])),k&&g&&(g=l<=q(k[1])),m?!g:g});return}a.value&&(o.value=s.matchMedia(e.toValue(t)),i.value=o.value.matches)}),O(o,"change",_,{passive:!0}),e.computed(()=>i.value)}function ae(t={}){const{window:n=W,initialWidth:s=Number.POSITIVE_INFINITY,initialHeight:l=Number.POSITIVE_INFINITY,listenOrientation:a=!0,includeScrollbar:d=!0,type:o="inner"}=t,i=e.shallowRef(s),_=e.shallowRef(l),u=()=>{if(n)if(o==="outer")i.value=n.outerWidth,_.value=n.outerHeight;else if(o==="visual"&&n.visualViewport){const{width:r,height:k,scale:g}=n.visualViewport;i.value=Math.round(r*g),_.value=Math.round(k*g)}else d?(i.value=n.innerWidth,_.value=n.innerHeight):(i.value=n.document.documentElement.clientWidth,_.value=n.document.documentElement.clientHeight)};u(),J(u);const m={passive:!0};return O("resize",u,m),n&&o==="visual"&&n.visualViewport&&O(n.visualViewport,"resize",u,m),a&&e.watch(oe("(orientation: portrait)"),()=>u()),{width:i,height:_}}const M=(t,n)=>{const s=t.__vccOpts||t;for(const[l,a]of n)s[l]=a;return s},le={class:"ai-chat-sidebar border-end p-3 d-flex flex-column"},ie={class:"ai-sidebar-nav d-flex flex-column gap-1"},re={class:"ai-sidebar-section-title d-flex align-items-center gap-2"},ce={class:"d-flex flex-column gap-2"},de=["onClick"],pe={class:"text-truncate flex-fill"},me=M({__name:"AiAssistantSidebar",setup(t){const n=e.inject("aiCurrentView",e.ref("draft")),s=e.inject("aiSessions",e.ref([])),l=e.inject("aiActiveSessionId",e.ref("")),a=e.inject("aiInputMessage",e.ref("")),d=e.ref(["recent"]),o=e.computed(()=>[...s.value].sort((m,r)=>r.updatedAt-m.updatedAt)),i=()=>{n.value="draft",a.value=""},_=m=>{l.value=m,n.value="chat"},u=m=>{s.value=s.value.filter(r=>r.id!==m),l.value===m&&(l.value="",n.value="draft",a.value="")};return(m,r)=>{const k=e.resolveComponent("a-icon"),g=e.resolveComponent("a-empty"),b=e.resolveComponent("a-button"),C=e.resolveComponent("a-collapse-panel"),y=e.resolveComponent("a-collapse");return e.openBlock(),e.createElementBlock("aside",le,[e.createElementVNode("div",ie,[e.createElementVNode("button",{class:e.normalizeClass(["ai-sidebar-nav-item",{active:e.unref(n)==="draft"}]),onClick:i},[e.createVNode(k,{type:"icon-edit"}),r[2]||(r[2]=e.createElementVNode("span",null,"新对话",-1))],2),e.createElementVNode("button",{class:e.normalizeClass(["ai-sidebar-nav-item",{active:e.unref(n)==="library"}]),onClick:r[0]||(r[0]=w=>n.value="library")},[e.createVNode(k,{type:"icon-appstore"}),r[3]||(r[3]=e.createElementVNode("span",null,"AI 指令库",-1))],2)]),e.createVNode(y,{activeKey:d.value,"onUpdate:activeKey":r[1]||(r[1]=w=>d.value=w),ghost:"",class:"ai-session-collapse flex-fill overflow-auto"},{default:e.withCtx(()=>[e.createVNode(C,{key:"recent"},{header:e.withCtx(()=>[e.createElementVNode("div",re,[e.createVNode(k,{type:"icon-history"}),r[4]||(r[4]=e.createElementVNode("span",null,"最近会话",-1))])]),default:e.withCtx(()=>[e.createElementVNode("div",ce,[o.value.length===0?(e.openBlock(),e.createBlock(g,{key:0,description:"暂无会话"})):e.createCommentVNode("",!0),(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(o.value,w=>(e.openBlock(),e.createElementBlock("div",{key:w.id,class:e.normalizeClass(["ai-session-item d-flex align-items-center gap-2",{active:e.unref(n)==="chat"&&w.id===e.unref(l)}]),onClick:V=>_(w.id)},[e.createElementVNode("span",pe,e.toDisplayString(w.title),1),e.createVNode(b,{type:"text",size:"small",class:"ai-session-delete",onClick:e.withModifiers(V=>u(w.id),["stop"])},{default:e.withCtx(()=>[e.createVNode(k,{type:"icon-delete"})]),_:1},8,["onClick"])],10,de))),128))])]),_:1})]),_:1},8,["activeKey"])])}}},[["__scopeId","data-v-ff65b680"]]),ue={class:"ai-instruction-library flex-fill overflow-auto bg-white p-4"},fe={class:"row g-3 mt-2"},_e=["onClick"],ge={class:"fw-semibold mb-2"},he={class:"small text-muted"},ye=M({__name:"AiInstructionLibrary",setup(t){const n=D.useStore(),s=e.ref(""),l=e.inject("aiInputMessage",e.ref("")),a=e.inject("aiActionType",e.ref("chat")),d=e.inject("aiCurrentView",e.ref("draft")),o=e.computed(()=>n.state.app.aiAssistantConfig||{}),i=e.computed(()=>{const m=o.value.instructions;return Array.isArray(m)?m:[]}),_=e.computed(()=>{const m=i.value||[],r=m.find(k=>k.label===s.value)||m[0];return Array.isArray(r?.items)?r.items:[]}),u=m=>{l.value=m.prompt||"",a.value=m.actionType||"chat",d.value="draft"};return e.watch(i,(m=[])=>{m.some(r=>r.label===s.value)||(s.value=m[0]?.label||"")},{immediate:!0}),(m,r)=>{const k=e.resolveComponent("a-tab-pane"),g=e.resolveComponent("a-tabs");return e.openBlock(),e.createElementBlock("div",ue,[r[1]||(r[1]=e.createElementVNode("div",{class:"text-center mb-4"},[e.createElementVNode("h3",{class:"mb-2"},"AI 指令库"),e.createElementVNode("div",{class:"text-muted"},"选择一个指令模板,快速开始当前系统的 AI 任务")],-1)),e.createVNode(g,{activeKey:s.value,"onUpdate:activeKey":r[0]||(r[0]=b=>s.value=b),centered:""},{default:e.withCtx(()=>[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(i.value,b=>(e.openBlock(),e.createBlock(k,{key:b.label,tab:b.label},null,8,["tab"]))),128))]),_:1},8,["activeKey"]),e.createElementVNode("div",fe,[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(_.value,b=>(e.openBlock(),e.createElementBlock("div",{key:b.prompt,class:"col-6 col-xl-4"},[e.createElementVNode("button",{class:"ai-instruction-card w-100 h-100 text-start bg-white rounded p-3",onClick:C=>u(b)},[e.createElementVNode("div",ge,e.toDisplayString(b.title),1),e.createElementVNode("div",he,e.toDisplayString(b.description),1)],8,_e)]))),128))])])}}},[["__scopeId","data-v-85d5df68"]]),be={class:"ai-message-bubble bg-light rounded p-3"},ke={class:"fw-semibold mb-2"},we={key:0,class:"mb-2"},xe={key:1,class:"small text-muted mb-2"},Ce={class:"ai-pre-wrap mb-0"},Ve=M({__name:"AiTableResultMessage",props:{message:{type:Object,required:!0}},setup(t){const n=t,s=e.computed(()=>(Array.isArray(n.message.columns)?n.message.columns:[]).map(o=>{const i=typeof o=="string"?o:o.key||o.dataIndex||o.title;return{title:typeof o=="string"?o:o.title||i,dataIndex:typeof o=="string"?o:o.dataIndex||i,key:i}})),l=e.computed(()=>(Array.isArray(n.message.rows)?n.message.rows:[]).map((o,i)=>({key:i,...o}))),a=e.computed(()=>JSON.stringify({columns:n.message.columns,rows:n.message.rows},null,2));return(d,o)=>{const i=e.resolveComponent("a-table");return e.openBlock(),e.createElementBlock("div",be,[e.createElementVNode("div",ke,e.toDisplayString(t.message.title||"表格结果"),1),t.message.summary?(e.openBlock(),e.createElementBlock("div",we,e.toDisplayString(t.message.summary),1)):e.createCommentVNode("",!0),t.message.sql?(e.openBlock(),e.createElementBlock("div",xe,"SQL:"+e.toDisplayString(t.message.sql),1)):e.createCommentVNode("",!0),e.createVNode(i,{class:"mb-3",size:"small",bordered:"",columns:s.value,"data-source":l.value,pagination:!1,scroll:{x:!0}},null,8,["columns","data-source"]),e.createElementVNode("pre",Ce,e.toDisplayString(a.value),1)])}}},[["__scopeId","data-v-de55b932"]]),Se={class:"small text-muted mb-2"},Ne={key:0,class:"ai-message-bubble bg-light rounded p-3"},Ae={class:"ai-pre-wrap text-warning-emphasis mb-3"},Ee={key:1,class:"ai-message-bubble bg-warning-subtle rounded p-3"},Be={class:"ai-pre-wrap text-warning-emphasis mb-0"},Ie={key:3,class:"ai-message-bubble bg-light rounded p-3"},Me={class:"fw-semibold mb-2"},$e={key:0,class:"mb-2"},Te={class:"small text-muted mb-2"},De={key:0},je={key:1},Le={key:1,class:"small text-muted mb-2"},Fe={class:"ai-pre-wrap mb-0"},Re={key:4,class:"ai-message-bubble bg-transparent p-0"},We={class:"ai-thinking-content"},Oe={class:"ai-thinking-content"},qe={key:0,class:"h-100 d-flex align-items-center justify-content-center text-muted"},ze=M({__name:"AiChatMessages",setup(t){const n=D.useStore(),s=e.inject("aiSessions",e.ref([])),l=e.inject("aiActiveSessionId",e.ref("")),a=e.inject("aiCurrentView",e.ref("draft")),d=e.computed(()=>n.state.app.aiAssistantConfig||{}),o=e.computed(()=>d.value.title||"AI 小助手"),i=e.computed(()=>d.value.welcomeMessage||""),_=e.ref(),u=e.computed(()=>{if(a.value==="draft")return[];const y=s.value.find(w=>w.id===l.value);return Array.isArray(y?.messages)?y.messages:[]});e.watch([l,()=>u.value.length],async()=>{await e.nextTick(),_.value.scrollTop=_.value.scrollHeight});const m=(y={})=>(Array.isArray(y.columns)?y.columns:[]).map(V=>({title:V,dataIndex:V,key:V})),r=(y={})=>(Array.isArray(y.rows)?y.rows:[]).map((V,I)=>({key:I,...V})),k=y=>`Thinking ${y||8}s`,g=y=>JSON.stringify(y.data||[],null,2),b=y=>Array.isArray(y)?y.join("、"):y,C=y=>y.role==="user"?"bg-primary-subtle text-dark p-3":y.type==="error"?"bg-danger-subtle text-danger border border-danger-subtle p-3":y.role==="assistant"?"bg-transparent p-0":"bg-light p-3";return(y,w)=>{const V=e.resolveComponent("a-table"),I=e.resolveComponent("a-collapse-panel"),$=e.resolveComponent("a-collapse");return e.openBlock(),e.createElementBlock("div",{ref_key:"messageWrapRef",ref:_,class:"ai-chat-messages flex-fill overflow-auto bg-white"},[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(u.value,(f,j)=>(e.openBlock(),e.createElementBlock("div",{key:j,class:e.normalizeClass(["d-flex flex-column mb-4",[f.role==="user"?"align-items-end":"align-items-start",f.type]])},[e.createElementVNode("div",Se,e.toDisplayString(f.role==="user"?"我":o.value),1),f.type==="sql_result"?(e.openBlock(),e.createElementBlock("div",Ne,[w[0]||(w[0]=e.createElementVNode("div",{class:"fw-semibold mb-2"},"执行 SQL:",-1)),e.createElementVNode("pre",Ae,e.toDisplayString(f.sql),1),e.createVNode(V,{size:"small",bordered:"",columns:m(f.result),"data-source":r(f.result),pagination:!1,scroll:{x:!0}},null,8,["columns","data-source"])])):f.type==="sql_preview"?(e.openBlock(),e.createElementBlock("div",Ee,[w[1]||(w[1]=e.createElementVNode("div",{class:"fw-semibold mb-2"},"SQL 预览:",-1)),e.createElementVNode("pre",Be,e.toDisplayString(f.content),1)])):f.type==="table_result"?(e.openBlock(),e.createBlock(Ve,{key:2,message:f},null,8,["message"])):f.type==="chart_result"?(e.openBlock(),e.createElementBlock("div",Ie,[e.createElementVNode("div",Me,e.toDisplayString(f.title||"图表结果"),1),f.summary?(e.openBlock(),e.createElementBlock("div",$e,e.toDisplayString(f.summary),1)):e.createCommentVNode("",!0),e.createElementVNode("div",Te,[e.createTextVNode(" 图表类型:"+e.toDisplayString(f.chartType||"未指定")+" ",1),f.xField?(e.openBlock(),e.createElementBlock("span",De,"|X 轴:"+e.toDisplayString(f.xField),1)):e.createCommentVNode("",!0),f.yFields?(e.openBlock(),e.createElementBlock("span",je,"|指标:"+e.toDisplayString(b(f.yFields)),1)):e.createCommentVNode("",!0)]),f.sql?(e.openBlock(),e.createElementBlock("div",Le,"SQL:"+e.toDisplayString(f.sql),1)):e.createCommentVNode("",!0),e.createElementVNode("pre",Fe,e.toDisplayString(g(f)),1)])):f.type==="thinking"?(e.openBlock(),e.createElementBlock("div",Re,[e.createVNode($,{ghost:"",class:"ai-thinking-collapse"},{default:e.withCtx(()=>[e.createVNode(I,{key:"thinking",header:k(f.thinkingSeconds)},{default:e.withCtx(()=>[e.createElementVNode("pre",We,e.toDisplayString(f.content),1)]),_:2},1032,["header"])]),_:2},1024)])):(e.openBlock(),e.createElementBlock("div",{key:5,class:e.normalizeClass(["ai-message-bubble ai-pre-wrap rounded",C(f)])},[f.thinking?(e.openBlock(),e.createBlock($,{key:0,ghost:"",class:"ai-thinking-collapse"},{default:e.withCtx(()=>[e.createVNode(I,{key:"thinking",header:k(f.thinkingSeconds)},{default:e.withCtx(()=>[e.createElementVNode("pre",Oe,e.toDisplayString(f.thinking),1)]),_:2},1032,["header"])]),_:2},1024)):e.createCommentVNode("",!0),e.createElementVNode("div",null,e.toDisplayString(f.content),1)],2))],2))),128)),u.value.length===0?(e.openBlock(),e.createElementBlock("div",qe,e.toDisplayString(i.value||"开始一个新的 AI 对话"),1)):e.createCommentVNode("",!0)],512)}}},[["__scopeId","data-v-8bae25ad"]]),Pe={class:"border-top px-4 py-3"},Ke={class:"ai-input-box d-flex flex-column gap-3 p-3 bg-white"},He={class:"d-flex align-items-center justify-content-between gap-3 w-100"},Ue={class:"d-flex align-items-center gap-2 min-w-0"},Ye={key:0,class:"small text-muted text-nowrap"},Ge={class:"d-flex align-items-center gap-2"},Qe=M({__name:"AiChatInput",setup(t){const n=D.useStore(),s=e.inject("aiSessions",e.ref([])),l=e.inject("aiActiveSessionId",e.ref("")),a=e.inject("aiCurrentView",e.ref("draft")),d=e.inject("aiInputMessage",e.ref("")),o=e.inject("aiActionType",e.ref("chat")),i=e.ref(!1),_=e.ref(""),u=e.computed(()=>n.state.app.aiAssistantConfig),m=e.computed(()=>u.value.title||"AI 小助手"),r=e.computed(()=>u.value.chatUrl),k=[{label:"聊天",value:"chat"},{label:"SQL",value:"sql"},{label:"表格",value:"table"},{label:"图表",value:"chart"}],g=e.computed(()=>u.value.models.map(p=>{const h=p.source||p.model_source||u.value.defaultModelSource||"online";return{...p,source:h,key:`${h}::${p.value}`}})),b=()=>{const p=u.value.defaultModelSource||"online",h=u.value.defaultModel;return g.value.find(c=>c.source===p&&c.value===h).key},C=e.ref(b()),y=e.computed(()=>g.value.find(p=>p.key===C.value)),w=e.computed(()=>a.value==="draft"?"":s.value.find(h=>h.id===l.value).debugLine),V=()=>"s_"+Date.now().toString(36)+"_"+Math.random().toString(36).slice(2,8),I=()=>({id:V(),title:"新对话",messages:[],debugLine:"",updatedAt:Date.now()}),$=()=>s.value.find(p=>p.id===l.value),f=()=>{const p=I();return s.value.unshift(p),l.value=p.id,a.value="chat",$()},j=(p,h)=>{p.messages.push({role:"user",content:h}),p.title==="新对话"&&(p.title=h),p.updatedAt=Date.now()},x=(p,h)=>{p.messages.push({role:"assistant",content:h}),p.updatedAt=Date.now()},A=(p,h,S)=>{for(const c of h)c.type==="ai"&&c.content?p.messages.push({role:"assistant",type:"ai",content:c.content,thinking:c.thinking,thinkingSeconds:S}):["thinking","thought","reasoning"].includes(c.type)&&c.content?p.messages.push({role:"assistant",type:"thinking",content:c.content,thinkingSeconds:S}):c.type==="sql_preview"&&c.content?p.messages.push({role:"assistant",type:"sql_preview",content:c.content}):c.type==="sql_result"?p.messages.push({role:"assistant",type:"sql_result",sql:c.sql,result:c.result}):c.type==="table_result"?p.messages.push({role:"assistant",type:"table_result",title:c.title,sql:c.sql,columns:c.columns,rows:c.rows,summary:c.summary}):c.type==="chart_result"?p.messages.push({role:"assistant",type:"chart_result",title:c.title,sql:c.sql,chartType:c.chart_type,xField:c.x_field,yFields:c.y_fields,data:c.data,summary:c.summary}):c.type==="error"&&c.content&&p.messages.push({role:"assistant",type:"error",content:c.content});p.updatedAt=Date.now()},T=async()=>{const p=d.value.trim();if(!p||i.value)return;const h=a.value==="draft"?f():$();j(h,p),d.value="",_.value="",i.value=!0;try{const S=await fetch("http://localhost:5011"+r.value,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({message:p,session_id:h.id,action_type:o.value,model_source:y.value.source,model:y.value.value})});if(!S.ok)throw new Error(`HTTP ${S.status}`);const c=await S.json();h.debugLine=tt(c);const L=c.steps||[];if(L.length>0){A(h,L,K(c));return}x(h,c.reply)}catch(S){_.value=`请求失败:${S.message}`}finally{i.value=!1}},K=p=>Math.max(1,Math.round(p.usage.eval_count/8)),tt=p=>{const h=p.usage,S=p.debug,c=`${(h.context_usage_ratio*100).toFixed(1)}%`;return`上下文:${h.prompt_eval_count} / ${h.context_limit}(${c})|回复:${h.eval_count}|历史:${S.history_message_count}`};return(p,h)=>{const S=e.resolveComponent("a-alert"),c=e.resolveComponent("a-textarea"),L=e.resolveComponent("a-select-option"),H=e.resolveComponent("a-select"),nt=e.resolveComponent("a-icon"),st=e.resolveComponent("a-button");return e.openBlock(),e.createElementBlock("div",Pe,[_.value?(e.openBlock(),e.createBlock(S,{key:0,class:"mb-3",message:_.value,type:"error","show-icon":""},null,8,["message"])):e.createCommentVNode("",!0),e.createElementVNode("div",Ke,[e.createVNode(c,{value:e.unref(d),"onUpdate:value":h[0]||(h[0]=N=>e.isRef(d)?d.value=N:null),placeholder:`给 ${m.value} 发送消息`,"auto-size":{minRows:2,maxRows:5},onKeydown:e.withKeys(e.withModifiers(T,["exact","prevent"]),["enter"])},null,8,["value","placeholder","onKeydown"]),e.createElementVNode("div",He,[e.createElementVNode("div",Ue,[e.createVNode(H,{value:e.unref(o),"onUpdate:value":h[1]||(h[1]=N=>e.isRef(o)?o.value=N:null),size:"small",class:"ai-action-type-select"},{default:e.withCtx(()=>[(e.openBlock(),e.createElementBlock(e.Fragment,null,e.renderList(k,N=>e.createVNode(L,{key:N.value,value:N.value},{default:e.withCtx(()=>[e.createTextVNode(e.toDisplayString(N.label),1)]),_:2},1032,["value"])),64))]),_:1},8,["value"]),w.value?(e.openBlock(),e.createElementBlock("span",Ye,e.toDisplayString(w.value),1)):e.createCommentVNode("",!0)]),e.createElementVNode("div",Ge,[e.createVNode(H,{value:C.value,"onUpdate:value":h[2]||(h[2]=N=>C.value=N),size:"small",class:"ai-model-select"},{default:e.withCtx(()=>[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(g.value,N=>(e.openBlock(),e.createBlock(L,{key:N.key,value:N.key},{default:e.withCtx(()=>[e.createTextVNode(e.toDisplayString(N.label),1)]),_:2},1032,["value"]))),128))]),_:1},8,["value"]),e.createVNode(st,{type:"primary",shape:"circle",class:"ai-send-btn",loading:i.value,onClick:T},{default:e.withCtx(()=>[i.value?e.createCommentVNode("",!0):(e.openBlock(),e.createBlock(nt,{key:0,type:"icon-send"}))]),_:1},8,["loading"])])])])])}}},[["__scopeId","data-v-e63f761d"]]),Xe={class:"ai-chat-wrap flex-fill d-flex bg-white"},Je={class:"flex-fill d-flex flex-column min-w-0"},Ze=M({__name:"AiAssistantModal",props:{open:{type:Boolean,default:!1}},emits:["close"],setup(t,{emit:n}){const s=n,l=D.useStore(),a=e.computed(()=>l.state.app.aiAssistantConfig||{}),d=e.computed(()=>a.value.title||"AI 小助手"),o=e.computed(()=>`gs-eant-comp:ai-assistant:${d.value}`),i=e.ref([]),_=e.ref(""),u=e.ref("draft"),m=e.ref(""),r=e.ref("chat");return(()=>{try{const g=localStorage.getItem(o.value);if(!g)return;const b=JSON.parse(g);Array.isArray(b.sessions)&&(i.value=b.sessions),b.activeSessionId&&(_.value=b.activeSessionId),_.value&&i.value.some(C=>C.id===_.value)&&(u.value="chat")}catch(g){console.warn("[gs-eant-comp] AI assistant storage parse failed:",g)}})(),e.watch([i,_],()=>{localStorage.setItem(o.value,JSON.stringify({activeSessionId:_.value,sessions:i.value}))},{deep:!0}),e.provide("aiSessions",i),e.provide("aiActiveSessionId",_),e.provide("aiCurrentView",u),e.provide("aiInputMessage",m),e.provide("aiActionType",r),(g,b)=>{const C=e.resolveComponent("a-modal");return e.openBlock(),e.createBlock(C,{open:t.open,title:d.value,width:"76vw",footer:null,"mask-closable":!0,"body-style":{padding:0},"wrap-class-name":"vh-90",onCancel:b[0]||(b[0]=y=>s("close"))},{default:e.withCtx(()=>[e.createElementVNode("div",Xe,[e.createVNode(me),e.createElementVNode("main",Je,[u.value==="library"?(e.openBlock(),e.createBlock(ye,{key:0})):(e.openBlock(),e.createElementBlock(e.Fragment,{key:1},[e.createVNode(ze),e.createVNode(Qe)],64))])])]),_:1},8,["open","title"])}}},[["__scopeId","data-v-0a4b31b9"]]),z=58,ve=132,B=16,P=M({__name:"AiAssistantTool",setup(t){const n=D.useStore(),s=e.ref(!1),l=e.ref(null),a=e.ref(!1),d=e.ref(null),o=e.ref(!1),i=e.ref(0),_=e.ref(0),u=e.ref(0),m=e.ref(0),{width:r,height:k}=ae(),g=e.ref(Math.max(B,window.innerWidth-z-24)),b=e.ref(Math.max(B,Math.round(window.innerHeight*.7))),C=(x,A,T)=>Math.min(Math.max(x,A),T),y=()=>{const x=Math.max(B,r.value-z-B),A=Math.max(B,k.value-ve-B);g.value=C(g.value,B,x),b.value=C(b.value,B,A)},w=x=>{!o.value||d.value!==x.pointerId||(g.value=u.value+x.clientX-i.value,b.value=m.value+x.clientY-_.value,y())},V=x=>{if(d.value!==x.pointerId)return;(Math.abs(x.clientX-i.value)>3||Math.abs(x.clientY-_.value)>3)&&(a.value=!0,window.setTimeout(()=>{a.value=!1},0)),o.value=!1,d.value=null,window.removeEventListener("pointermove",w),window.removeEventListener("pointerup",V)},I=x=>{x.button===0&&(d.value=x.pointerId,o.value=!0,i.value=x.clientX,_.value=x.clientY,u.value=g.value,m.value=b.value,window.addEventListener("pointermove",w),window.addEventListener("pointerup",V))},$=()=>{a.value||(s.value=!0)};e.watch([r,k],y,{immediate:!0});const f=e.computed(()=>!!n.state.app.aiAssistantConfig?.enabled),j=e.computed(()=>({left:`${g.value}px`,top:`${b.value}px`}));return(x,A)=>{const T=e.resolveComponent("a-button");return f.value?(e.openBlock(),e.createElementBlock("div",{key:0,ref_key:"aiFloatingRef",ref:l,class:"floating-ai",style:e.normalizeStyle(j.value),onPointerdown:I},[e.createVNode(T,{class:"tool-btn ai-btn",onClick:$},{default:e.withCtx(()=>[...A[1]||(A[1]=[e.createElementVNode("span",{class:"ai-mark"},"Ai",-1),e.createElementVNode("span",{class:"ai-label"},"小助手",-1)])]),_:1}),e.createVNode(Ze,{open:s.value,onClose:A[0]||(A[0]=K=>s.value=!1)},null,8,["open"])],36)):e.createCommentVNode("",!0)}}},[["__scopeId","data-v-83236aae"]]),et={install:t=>{t.component("AiAssistantTool",P)}};E.AiAssistantTool=P,E.default=et,Object.defineProperties(E,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})}));
|
package/dist/vite.svg
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
package/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
declare module 'gs-ai-assistant';
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "gs-ai-assistant",
|
|
3
|
+
"private": false,
|
|
4
|
+
"version": "1.0.0-beta.0",
|
|
5
|
+
"main": "dist/gs-eant-comp.umd.cjs",
|
|
6
|
+
"module": "dist/gs-eant-comp.js",
|
|
7
|
+
"types": "index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist",
|
|
10
|
+
"index.d.ts"
|
|
11
|
+
],
|
|
12
|
+
"type": "module",
|
|
13
|
+
"scripts": {
|
|
14
|
+
"dev": "vite",
|
|
15
|
+
"build": "vite build",
|
|
16
|
+
"preview": "vite preview",
|
|
17
|
+
"gusean": "vite build",
|
|
18
|
+
"test": "vitest"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"@vueuse/core": "^14.3.0",
|
|
22
|
+
"ant-design-vue": "^4.2.6",
|
|
23
|
+
"axios": "^1.13.2",
|
|
24
|
+
"grid-layout-plus": "^1.1.1",
|
|
25
|
+
"gs-eant-comp": "^3.1.8-beta.9",
|
|
26
|
+
"gs-flow-engine": "^2.2.6",
|
|
27
|
+
"nprogress": "^0.2.0",
|
|
28
|
+
"qs": "^6.14.0",
|
|
29
|
+
"vue": "^3.5.25",
|
|
30
|
+
"vue-request": "^2.0.4",
|
|
31
|
+
"vue-router": "^4.6.3",
|
|
32
|
+
"vue3-colorpicker": "^2.3.0",
|
|
33
|
+
"vue3-slide-verify": "^1.1.8",
|
|
34
|
+
"vuedraggable": "^4.1.0",
|
|
35
|
+
"vuex": "^4.1.0"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@vitejs/plugin-vue": "^6.0.1",
|
|
39
|
+
"bootstrap": "^5.3.8",
|
|
40
|
+
"less": "^4.4.2",
|
|
41
|
+
"vite": "^7.2.4"
|
|
42
|
+
}
|
|
43
|
+
}
|