Browse Source

Merge branch 'han_v3'

space_permission
herenshan112 4 months ago
parent
commit
ab597ecbbd
  1. 4
      src/api/DesignForm/filterUnit.ts
  2. 6
      src/api/DesignForm/types.ts
  3. 1
      src/api/DesignForm/utils.ts
  4. 11
      src/api/doc/space.ts
  5. 64
      src/components/DesignForm/formControlPropertiNew.vue
  6. 12
      src/components/DesignForm/public/expand/digitpage.vue
  7. 177
      src/components/DesignForm/public/form/aiassist.vue
  8. 74
      src/components/DesignForm/public/form/form.vue
  9. 15
      src/components/DesignForm/public/form/formItem.vue

4
src/api/DesignForm/filterUnit.ts

@ -12,6 +12,8 @@ const analysisFromUnit = (unitInfo:formStruct) => {
unitInfo.formData.list.forEach((item:any) => {
// console.log("解析出表单可作为AI变量的元素------1---1--->",item.label?1:2)
if(!layoutUnit.includes(item.type)){
//by han2015: 暂时只支持普通类型字段
if (item.type!='input' && item.type!='digitpage') return;
let labelName = ""
if(item.label){
labelName = item.label
@ -20,7 +22,7 @@ const analysisFromUnit = (unitInfo:formStruct) => {
}else{
labelName = item.unitName
}
console.log("解析出表单可作为AI变量的元素----2--1-1----->",item)
//console.log("解析出表单可作为AI变量的元素----2--1-1----->",item)
optionsInfo.push({
label:labelName,
value:item.name

6
src/api/DesignForm/types.ts

@ -57,6 +57,12 @@ export interface FormData {
labelStyle:{},
inputStyle:{}
}
aiConfig?:{
library:string[];
title:string[];
trigger:number;
openShowType:number;
}[]
}
export interface TableData {

1
src/api/DesignForm/utils.ts

@ -106,3 +106,4 @@ export const constSetFormOptions = prefix + 'SetFormOptions' // 使用setOptions
export const constGetControlByName = prefix + 'GetControlByName' // 根据name从formData.list查找数据
export const constFormBtnEvent = prefix + 'FormBtnEvent' // 按钮组件事件
export const constFormProps = prefix + 'FormProps' // 按钮组件事件
export const constAiEffect = prefix + 'AiEffect' // 表单组件触发AI查询事件

11
src/api/doc/space.ts

@ -178,4 +178,15 @@ export function setAiChat(data: any){
method: 'post',
data: data
});
}
/**
*
*/
export function getAiagentList(data?: any){
return request({
url: '/aibot/agent/list',
method: 'post',
data: data
});
}

64
src/components/DesignForm/formControlPropertiNew.vue

@ -21,6 +21,10 @@ import {
optionsInfo,
} from "@/api/DesignForm/types";
import {
getAiagentList
} from "@/api/doc/space";
import {
chineseToPinyin,
customerFormGroupList,
@ -3561,6 +3565,14 @@ const gainFormGroupList = () => {
}
});
};
//by han2015
const gainAiagentList=()=>{
getAiagentList().then(resp=>{
aiAgentList.value=resp.data
})
};
//liwenxuan 2025 start
const scanTypes = [
{
@ -3666,6 +3678,7 @@ watch(
onMounted(() => {
gainFormGroupList();
analysisFromUnit(props.state);
gainAiagentList()
});
watch(
@ -4033,24 +4046,31 @@ const addPickTracn = () => {
];
}
};
function delList(dex:number){
if(props.formInfo.aiConfig){
props.formInfo.aiConfig.splice(dex,1)
}
}
/**
@ 作者: 秦东
@ 时间: 2025-04-10 08:12:21
@ 功能: 知识库
*/
const libraryList = ref([
{
label: "法律法规",
value: 1,
},
{
label: "安全环保",
value: 2,
},
{
label: "员工守则",
value: 3,
},
const aiAgentList = ref([
// {
// label: "",
// value: 1,
// },
// {
// label: "",
// value: 2,
// },
// {
// label: "",
// value: 3,
// },
]);
</script>
<template>
@ -5424,9 +5444,9 @@ const libraryList = ref([
</el-form-item>
<el-form-item label="触发方式">
<el-radio-group v-model="item.trigger">
<el-radio :value="1">全部有值</el-radio>
<el-radio :value="2">任一有值</el-radio>
<el-radio :value="3">半数以上有值</el-radio>
<el-radio :value="1">任一有值</el-radio>
<el-radio :value="2">半数以上有值</el-radio>
<el-radio :value="3">全部有值</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="采用的知识库">
@ -5437,14 +5457,14 @@ const libraryList = ref([
placeholder="请选择采用的知识库"
>
<el-option
v-for="lItem in libraryList"
:key="lItem.value"
:label="lItem.label"
:value="lItem.value"
v-for="lItem in aiAgentList"
:key="lItem.uuid"
:label="lItem.name"
:value="lItem.uuid"
/>
</el-select>
</el-form-item>
<el-form-item label="结果呈现方式">
<!-- <el-form-item label="结果呈现方式">
<el-radio-group v-model="item.openShowType">
<el-radio :value="1">底部展示</el-radio>
<el-radio :value="2">消息弹出框</el-radio>
@ -5452,7 +5472,7 @@ const libraryList = ref([
<el-radio :value="4">消息提示</el-radio>
<el-radio :value="5">通知框</el-radio>
</el-radio-group>
</el-form-item>
</el-form-item> -->
</el-form>
</el-card>

12
src/components/DesignForm/public/expand/digitpage.vue

@ -10,6 +10,7 @@ import {
constControlChange,
constSetFormOptions,
constFormProps,
constAiEffect,
constGetControlByName,
} from "@/api/DesignForm/utils";
import {
@ -40,6 +41,14 @@ const value = computed({
const config = computed(() => {
return props.data.config || {};
});
//----------by han2015: support AI event emitting----------------
const changeEvent = inject(constAiEffect, '') as any
function onValueChange(){
changeEvent &&
changeEvent({key:props.data.name,value:props.modelValue, field:props.data.item.label})
}
//--------------------------------------
/**
@ 作者: 秦东
@ 时间: 2024-03-01 09:07:11
@ -70,6 +79,7 @@ const getInputSlot = (key?: string) => {
}
return control;
};
/**
@ 作者: 秦东
@ 时间: 2024-07-27 15:11:42
@ -128,6 +138,7 @@ const judgeIsDisabled = (key: string) => {
v-model="value"
:style="getFormItemInputStyle(configStyle, 2)"
:input-style="getFormItemInputStyle(configStyle, 3)"
@change="onValueChange"
oninput="value=value.replace(/[^\d.]/g, '').replace(/\.{2,}/g, '.').replace('.', '$#$').replace(/\./g, '').replace('$#$', '.').replace(/^\./g, '')"
placeholder="请输入"
>
@ -138,7 +149,6 @@ const judgeIsDisabled = (key: string) => {
:disabled="judgeIsDisabled(data.name)"
:transform-option="transformOption"
type="slot"
@change="inputSlotChange"
/>
</div>
<span v-else>{{ config.append }}</span>

177
src/components/DesignForm/public/form/aiassist.vue

@ -0,0 +1,177 @@
<!--
@ 作者: han2015
@ 时间: 2025-05-12 15:39:13
@ 备注: aibot组件
-->
<script lang="ts" setup>
import { doAiChat,aiChatData} from "@/api/doc/space"
import {ElText,ElInput, ButtonInstance} from "element-plus";
import { VueMarkdown } from '@crazydos/vue-markdown'
import rehypeRaw from 'rehype-raw'
import remarkGfm from 'remark-gfm'
//
const checkedModel = ref([])
const baseURL=import.meta.env.VITE_APP_BASE_API
const conversation=ref("") //uuid
const myquestion=ref('')
const controller = ref<AbortController | null>(null)
const interact_msg=ref<{ask:boolean,think:string,content:string}[]>([])
const props = withDefaults(defineProps<{
//closefunc:()=>void,
//agent:{model:boolean,name:string,uuid:string[]}
}>(),{})
//
interface message{
ask:boolean,
think:string,
content:string
}
//
interface chatRecord{
uuid:string,
agentuuid:string,
brief:string,
messages:message[]
}
/* 中断函数,供按钮调用 */
function abortFetch() {
if (controller.value) {
controller.value.abort()
controller.value = null
}
}
defineExpose({onSendParamToAI})
async function onSendParamToAI(user:string,arr:Array<{ uuids: string[]; params: { [key: string]: any } }>){
interact_msg.value=[]
for (let ele of arr){
interact_msg.value.unshift({ask:true,think:"", content:"AI正在分析。。。"})
for (let uid of ele.uuids){
await doRequest(user,uid,ele.params)
}
}
}
async function doRequest(_user:string,uuid:string,param:any){
let mRespMsg=""
const params={
"onlineSearch":"否",
"useDataset":"否"
}
for (let item of checkedModel.value){
if(item==="onlineSearch") params.onlineSearch="是"
if(item==="useDataset") params.useDataset="是"
}
controller.value = new AbortController();
try{
const res= await doAiChat(`${baseURL}/aibot/assisted/${uuid}/chat`,{
inputs: params,
query:JSON.stringify(param),
response_mode:"streaming",
conversation_id:"",//conversation.value,
user:_user,//base64
},controller.value.signal
)
if (!res.ok) {
throw new Error(`HTTP ${res.status} ${res.statusText}`);
}
const reader = res.body!.getReader();
const decoder = new TextDecoder('utf-8');
let chunk = ''; //
while (true) {
const {done, value} = await reader.read()
if (done) break;
//
chunk += decoder.decode(value, {stream: true});
const lines = chunk.split(/\n/);
chunk = lines.pop() || ''
for (const line of lines) {
if (!line.trim()) continue; //
if (line.startsWith('data: ')) {
const data = line.slice(6);
const json = JSON.parse(data);
if(json.event==="message"){
//conversation.value=json.conversation_id
mRespMsg+=json.answer
}
}
}
}
}catch (e: any) {
if (e.name === 'AbortError') {
console.log('用户手动中断')
}
}
interact_msg.value.unshift({ask:true,think:"", content:JSON.stringify(param)})
const arr=mRespMsg.split("</think>")
if(arr.length===1){
interact_msg.value.unshift({ask:false,think:"",content:arr[0]})
}else{
//
interact_msg.value.unshift({ask:false,think:arr[0],content:arr[1]})
}
}
function resetContext(){
interact_msg.value=[]
conversation.value=""
//props.closefunc()
}
//
// onMounted(() => {
// });
</script>
<template>
<div :style="{backgroundColor:'#f3f3f3'}">
<div class="reply_area" >
<template v-for="msg of interact_msg">
<div v-if="msg.ask" class="t_ask" >{{ msg.content }}</div>
<div v-else class="t_resp">
{{ msg.content }}
<!-- <VueMarkdown :markdown="msg.content"></VueMarkdown> -->
</div>
</template>
</div>
</div>
</template>
<style lang="scss" scoped>
.reply_area{
width: 260px;
background: white;
overflow-y: auto;
display: flex;
flex-direction: column;
overflow-wrap:anywhere;
}
.t_ask{
margin: 5px;
align-self: end;
background-color: rgb(188 211 241);
border-radius:10px;
}
.t_resp{
margin: 5px;
align-self: start;
color: black;
background-color: rgb(222, 243, 222);
}
</style>

74
src/components/DesignForm/public/form/form.vue

@ -21,6 +21,7 @@ import {
constControlChange,
constFormProps,
appendOrRemoveStyle,
constAiEffect,
} from "@/api/DesignForm/utils";
import formatResult from "@/utils/DesignForm/formatResult";
import formChangeValue from "@/utils/DesignForm/formChangeValue";
@ -75,6 +76,7 @@ const props = withDefaults(
labelStyle: {},
inputStyle: {},
},
aiConfig:[]
};
},
dict: () => {
@ -156,6 +158,13 @@ const resultDict = ref({});
const model = ref<any>({});
// model
const getInitModel = () => {
if(props.formData.aiConfig?.length>0){
props.formData.aiConfig?.forEach(item=>{
currentAgent.value.push({name:"test",model:false,uuid:item.library,fields:item.title,trigger:item.trigger,params:{}})
})
}
const obj = {};
forEachGetFormModel(props.formData.list, obj);
// console.log("obj===>",obj)
@ -484,6 +493,39 @@ watch(
{ deep: true }
);
//-----------------------AI setting--------------------------
//AIform
const currentAgent=ref<{model:boolean,name:string,uuid:string[],fields:string[],trigger:number,params:{[key: string]: any}}[]>([])
const aiassistRef=ref()
//AI
provide(constAiEffect, ({ key, value, field}: any) => {
//ai_envents
const ai_events: Array<{ uuids: string[]; params: { [key: string]: any } }> = [];
currentAgent.value.forEach(ag=>{
if(ag.fields.includes(key)){ //trigger: 1: 2 3
ag.params[field]=value;//keyfieldName
switch(ag.trigger){
case 2:
if(Object.keys(ag.params).length>=ag.fields.length/2){
ai_events.push({uuids:ag.uuid,params:ag.params})
}
break;
case 3:
if(Object.keys(ag.params).length==ag.fields.length){
ai_events.push({uuids:ag.uuid,params:ag.params})
}
break;
default:
ai_events.push({uuids:ag.uuid,params:ag.params})
}
}
})
if(ai_events.length>0){
aiassistRef.value.onSendParamToAI(props.formData.form.formName,ai_events)
}
})
//------------------------------------------------------------
// tProp
provide(constControlChange, ({ key, value, data, tProp, type, attribute }: any) => {
// console.log("----------1--------->", key);
@ -493,6 +535,7 @@ provide(constControlChange, ({ key, value, data, tProp, type, attribute }: any)
// console.log("----------5--------->", type);
// console.log("----------6--------->", attribute);
// console.log("----------11--------->", model.value);
let fieldVal = {};
for (let i in model.value) {
if (i == key) {
@ -518,7 +561,6 @@ provide(constControlChange, ({ key, value, data, tProp, type, attribute }: any)
let newFormConfig = props.formData.config.groupKey;
let odlHideField = props.formData.config.hideField;
delete props.formData.config.groupKey;
console.log(props.formData);
delete props.formData.config.hideField;
let sendInfo = {
fieldKey: key,
@ -556,13 +598,11 @@ provide(constControlChange, ({ key, value, data, tProp, type, attribute }: any)
}
props.formData.config.groupKey = newFormConfig;
props.formData.config.hideField = odlHideField;
console.log(props.formData);
});
})
.finally(() => {
props.formData.config.groupKey = newFormConfig;
props.formData.config.hideField = odlHideField;
console.log(props.formData);
});
}
// })
@ -715,8 +755,6 @@ function showOrHide(data: any) {
//console.log(leftOperatorsAndRight)
//console.log(data)
if (data.name == leftArr[2]) {
console.log("ghasdhasdfhhsadhasd");
console.log(props.formData.list[i].name);
nextTick(() => {
console.log(model.value[leftArr[2]]);
if (leftOperatorsAndRight.operator == "==") {
@ -2145,7 +2183,8 @@ const webPage = computed({
<slot></slot>
</el-form>
</div>
<div v-else v-loading="loading" class="pcBox">
<div v-else v-loading="loading" class="pcBox" :class="{boxAI:type!=5 && currentAgent.length>0}">
<Aiassist ref="aiassistRef" v-if="type!=5 && currentAgent.length>0" :agent="currentAgent"></Aiassist>
<el-form
v-bind="formData.form"
ref="ruleForm"
@ -2168,6 +2207,8 @@ const webPage = computed({
<slot></slot>
</el-form>
</div>
</template>
<style lang="scss" scoped>
.webBox {
@ -2188,4 +2229,25 @@ const webPage = computed({
overflow-x: hidden;
position: relative;
}
.boxAI{
display: grid;
grid-template-columns:1fr 4fr;
}
.t_ask{
align-self: end;
line-height: 34px;
background-color: rgb(188 211 241);
padding: 0 30px;
border-radius:10px;
margin: 15px;
}
.t_resp{
align-self: start;
line-height: 30px;
margin: 20px 33px;
font-size: 18px;
color: black;
}
</style>

15
src/components/DesignForm/public/form/formItem.vue

@ -16,6 +16,7 @@ import {
constControlChange,
constSetFormOptions,
constFormProps,
constAiEffect,
constGetControlByName,
} from "@/api/DesignForm/utils";
import validate from "@/api/DesignForm/validate";
@ -122,6 +123,17 @@ const updateModel = (val: any) => {
attribute: controlAttribute,
});
};
//----------by han2015: support AI event emitting----------------
//changeEventchangeEventfieldChange
const fieldChangeEnt = inject(constAiEffect, '') as any
function onValueChange(_type:string){
if(_type=="password") return;
fieldChangeEnt &&
fieldChangeEnt({key:props.data.name,value:props.modelValue, field:props.data.item.label})
}
//--------------------------------------
const value = computed({
get() {
if (props.tProp) {
@ -1222,10 +1234,11 @@ const diGuiJilian = (val: any, options: any[]) => {
:style="getFormItemInputStyle(configStyle, 2)"
:input-style="getFormItemInputStyle(configStyle, 3)"
v-if="['input', 'password'].includes(data.type)"
@change="onValueChange(data.type)"
:placeholder="
data.control.placeholder
? data.control.placeholder
: '请输入' + getLabel(data.item)
: '请输入>>>' + getLabel(data.item)
"
>
<template #prepend v-if="config.prepend">

Loading…
Cancel
Save