You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
297 lines
9.5 KiB
297 lines
9.5 KiB
<template>
|
|
<view class="min-height bg-main-light">
|
|
<HeaderItem title="AI智慧助手"/>
|
|
<view style="line-height: 35rpx"
|
|
class="flex flex-col justify-start items-start text-25 p-30">
|
|
<view class="text-25 text-gray text-center my-15 w-100p">该内容由人工智能生成</view>
|
|
<view v-for="(item, index) in list" :key="index" class="mb-25 w-100p">
|
|
<view v-if="!item.isMine" class="flex justify-start items-start">
|
|
<u-icon name="/static/robot.png" size="60rpx"/>
|
|
<view class="shadow bg-white ml-15" style="border-radius: 0 15rpx 15rpx 15rpx; max-width: 80%">
|
|
<view v-if="item.loading" class="p-15">
|
|
<u-loading-icon mode="semicircle" :color="MAIN()"></u-loading-icon>
|
|
</view>
|
|
<template v-else>
|
|
<template v-if="item.type !== 'connect'">
|
|
<zero-markdown-view v-if="item.type === 'text'" :markdown="item.content"></zero-markdown-view>
|
|
<view v-else-if="item.type === 'bill'">
|
|
<template v-if="billList.length">
|
|
<BillItem v-for="(bill, billIndex) in billList" :item="bill" :key="billIndex"/>
|
|
<view class="p-30">
|
|
<u-button type="primary" shape="circle" @click="$jump('/pages/user/property-bill')">去缴费
|
|
</u-button>
|
|
</view>
|
|
</template>
|
|
<view class="flex flex-col justify-center items-center mt-50" v-else>
|
|
<u-icon name="/static/empty-bill.png" size="200rpx"/>
|
|
<text class="text-gray mt-20">暂无账单</text>
|
|
</view>
|
|
</view>
|
|
<view v-else-if="item.type === 'link'" class="p-30">
|
|
<text class="text-blue mt-20" @click="$jump(item.url)">点击跳转</text>
|
|
</view>
|
|
</template>
|
|
</template>
|
|
|
|
</view>
|
|
</view>
|
|
<view v-else class="flex justify-end items-start w-100p">
|
|
<view class="shadow p-15 text-white"
|
|
style="border-radius: 15rpx 0 15rpx 15rpx; max-width: 80%; background-color: #006DFF">{{
|
|
item.content
|
|
}}
|
|
</view>
|
|
</view>
|
|
<!-- <view v-if="index === 0" class="mt-25">-->
|
|
<!-- <view class="font-bold text-28 mb-25 text-center">猜你想问</view>-->
|
|
<!-- <view class="font-bold text-28 mb-25 text-center" @click="send(quest.dictDataCode)"-->
|
|
<!-- style="color: #006DFF"-->
|
|
<!-- v-for="(quest, questIndex) in questionList" :key="questIndex">-->
|
|
<!-- {{ quest.dictDataCode }}-->
|
|
<!-- </view>-->
|
|
<!-- </view>-->
|
|
</view>
|
|
<u-gap height="140rpx"></u-gap>
|
|
</view>
|
|
<view class="stop" v-if="answering" @click="stopAI">
|
|
<u-icon name="/static/stop.png" width="80rpx" height="80rpx"/>
|
|
</view>
|
|
<view class="footer">
|
|
<view class="p-20 bg-white shadow-top flex justify-center items-center">
|
|
<view class="flex-1 mr-15">
|
|
<u-textarea maxlength="-1" auto-height v-model="content" border="none" placeholder="点此开始提问"/>
|
|
</view>
|
|
<view class="mr-25">
|
|
<u-icon name="/static/send.png" size="60rpx" @click="send()"/>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script>
|
|
import HeaderItem from "@/components/HeaderItem.vue";
|
|
import {WS_API} from "@/config";
|
|
import {sendChatReq, stopChatReq} from "@/api/lawOrg";
|
|
import {getUserInfo} from "@/util/user";
|
|
import {MAIN} from "@/config/color";
|
|
import {dictDataReq} from "@/api/common";
|
|
import {userRoomListReq} from "@/api/room";
|
|
import {listBillReq} from "@/api/bill";
|
|
import BillItem from "@/pages/ai/components/BillItem.vue";
|
|
|
|
export default {
|
|
name: "index",
|
|
components: {BillItem, HeaderItem},
|
|
data() {
|
|
return {
|
|
list: [],
|
|
questionList: [],
|
|
content: '',
|
|
taskId: null,
|
|
roomList: null,
|
|
answering: false,
|
|
billList: [],
|
|
}
|
|
},
|
|
methods: {
|
|
MAIN() {
|
|
return MAIN
|
|
},
|
|
async getQuestionsList() {
|
|
const {data} = await dictDataReq({dictId: '165'})
|
|
this.questionList = data
|
|
},
|
|
async getWelcomeWord() {
|
|
const {data} = await dictDataReq({dictId: '1435'})
|
|
this.list.push({
|
|
content: data[0].dictDataCode,
|
|
isMine: false,
|
|
loading: false,
|
|
done: true,
|
|
type: 'text'
|
|
})
|
|
console.log(this.list)
|
|
},
|
|
async send(content = null) {
|
|
const contentItem = content || this.content
|
|
// console.log(contentItem, this.content)
|
|
if (!contentItem.trim()) return this.$toast('请输入提问内容')
|
|
if (!this.list[this.list.length - 1].done) return this.$toast('请等待AI回答完毕再继续提问')
|
|
this.list.push({
|
|
content: contentItem,
|
|
isMine: true,
|
|
loading: false,
|
|
done: true,
|
|
type: 'text'
|
|
})
|
|
this.scrollToBottom()
|
|
this.answering = true
|
|
this.list.push({
|
|
content: '',
|
|
isMine: false,
|
|
loading: true,
|
|
done: false,
|
|
})
|
|
this.taskId = null
|
|
sendChatReq({
|
|
query: contentItem,
|
|
user: getUserInfo().uid
|
|
}).then(() => {
|
|
this.list[this.list.length - 1].done = true
|
|
this.answering = false
|
|
})
|
|
this.content = ''
|
|
},
|
|
scrollToBottom() {
|
|
setTimeout(() => {
|
|
this.$nextTick(() => {
|
|
uni.pageScrollTo({
|
|
scrollTop: 99999,
|
|
duration: 0
|
|
})
|
|
})
|
|
}, 100)
|
|
},
|
|
async stopAI() {
|
|
await stopChatReq({
|
|
taskId: this.taskId
|
|
})
|
|
this.answering = false
|
|
uni.closeSocket()
|
|
},
|
|
async getRoomList() {
|
|
const {data} = await userRoomListReq()
|
|
this.roomList = data.map(item => {
|
|
item.title = ''
|
|
if (item.villageName) item.title += item.villageName
|
|
if (item.buildingName) item.title += `-${item.buildingName}`
|
|
if (item.unitName) item.title += `-${item.unitName}`
|
|
if (item.roomNumber) item.title += `-${item.roomNumber}`
|
|
return item
|
|
})
|
|
if (this.roomList.length) {
|
|
await this.getBillData()
|
|
}
|
|
},
|
|
async getBillData() {
|
|
this.billList = []
|
|
this.totalAmount = 0
|
|
const params = {
|
|
roomIdList: this.roomList.map(item => item.baseRoomRoomCode).join(),
|
|
billState: 2,
|
|
}
|
|
try {
|
|
this.loading = true
|
|
const {data} = await listBillReq(params).finally(() => {
|
|
this.loading = false
|
|
uni.hideLoading()
|
|
})
|
|
this.billList = data.map(item => {
|
|
item.show = true
|
|
item.selected = true
|
|
item.totalAmount = 0
|
|
item.bills.map(bill => {
|
|
item.totalAmount += bill.billAmount
|
|
return bill
|
|
})
|
|
item.totalAmount = item.totalAmount.toFixed(2)
|
|
return item
|
|
})
|
|
// this.calTotalAmount()
|
|
console.log(this.billList)
|
|
} catch (error) {
|
|
console.error('获取账单数据失败:', error);
|
|
}
|
|
},
|
|
},
|
|
onLoad() {
|
|
|
|
uni.connectSocket({
|
|
url: `${WS_API}/aiUser`
|
|
})
|
|
uni.onSocketMessage(async res => {
|
|
if (res.data === '连接成功') return
|
|
const aiData = JSON.parse(res.data)
|
|
this.list[this.list.length - 1].loading = false
|
|
if (aiData.answer !== '__END__') {
|
|
this.list[this.list.length - 1].type = 'text'
|
|
this.list[this.list.length - 1].content += aiData.answer
|
|
} else {
|
|
const lastContent = this.list[this.list.length - 1].content
|
|
console.log('check url', lastContent, lastContent.includes(`<openUrl url="/pages/user/property-bill">`))
|
|
if (lastContent.includes(`<openUrl url="/pages/user/property-bill">`)) {
|
|
await this.getRoomList()
|
|
this.list.push({
|
|
content: '',
|
|
isMine: false,
|
|
loading: false,
|
|
done: true,
|
|
type: 'bill'
|
|
})
|
|
} else if (lastContent.includes(`servicePages/pages/suggest`) || lastContent.includes(`<openUrl url="/servicePages/pages/suuggest">`)) {
|
|
this.list.push({
|
|
content: '点击跳转',
|
|
isMine: false,
|
|
loading: false,
|
|
done: true,
|
|
type: 'link',
|
|
url: '/servicePages/pages/suggest'
|
|
})
|
|
} else if (lastContent.includes(`servicePages/pages/survey`)) {
|
|
this.list.push({
|
|
content: '点击跳转',
|
|
isMine: false,
|
|
loading: false,
|
|
done: true,
|
|
type: 'link',
|
|
url: '/servicePages/pages/survey'
|
|
})
|
|
} else if (lastContent.includes(`<openUrl url="/servicePages/pages/fix">`)) {
|
|
this.list.push({
|
|
content: '点击跳转',
|
|
isMine: false,
|
|
loading: false,
|
|
done: true,
|
|
type: 'link',
|
|
url: '/servicePages/pages/fix'
|
|
})
|
|
}
|
|
}
|
|
this.taskId = aiData.taskId
|
|
this.scrollToBottom()
|
|
console.log(this.list)
|
|
})
|
|
this.getWelcomeWord()
|
|
},
|
|
onUnload() {
|
|
this.stopAI()
|
|
},
|
|
onHide() {
|
|
this.stopAI()
|
|
},
|
|
}
|
|
</script>
|
|
<style scoped>
|
|
page {
|
|
background-color: #E0F2FE;
|
|
}
|
|
|
|
.bg {
|
|
background: url("https://sifa-api.wsdns.cn/api/file/20250420/bg.jpg") no-repeat 100% 100%;
|
|
}
|
|
|
|
.stop {
|
|
position: fixed;
|
|
right: 10rpx;
|
|
bottom: 160rpx;
|
|
width: 100rpx;
|
|
height: 100rpx;
|
|
border-radius: 100rpx;
|
|
background: rgba(255, 255, 255, 0.4);
|
|
box-shadow: 1px 1px 5px #3c9cff;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
</style>
|