first commit

This commit is contained in:
2025-05-22 10:33:32 +08:00
commit f2ef63d910
581 changed files with 53162 additions and 0 deletions
+36
View File
@@ -0,0 +1,36 @@
<template>
<view class="min-height bg-main-light p-30">
<HeaderItem title="AI律师咨询"/>
<view class="footer">
<view class="p-20 bg-white shadow-top flex justify-center items-center">
<view class="flex-1 mr-15">
<u-input v-model="content" border="none" placeholder=""/>
</view>
<u-icon name="/static/send.png" size="60rpx"/>
</view>
</view>
</view>
</template>
<script>
import CustomTabbar from "@/components/customTabbar.vue";
import HeaderItem from "@/components/HeaderItem.vue";
export default {
name: "index",
components: {HeaderItem, CustomTabbar},
data() {
return {
list: [],
content: ''
}
},
methods: {},
onLoad() {
this.list.push({
content: '您好!我是法律机器人,请问您想咨询什么问题呢?',
isMine: false
})
}
}
</script>
+38
View File
@@ -0,0 +1,38 @@
<template>
<view class="min-height bg-main-light">
<HeaderItem title="法律计算器"/>
<view class="flex justify-start items-start flex-wrap">
<view class="card flex flex-col justify-center items-center m-15"
v-for="(item, index) in list" :key="index"
@click="$jump(`/userPages/pages/calDetail?id=${item.id}&title=${item.title}`)"
style="flex: 0 0 40%; border-radius: 20rpx">
<u-icon :name="item.icon" size="120rpx"/>
<text class="text-25 mt-10">{{ item.title }}</text>
</view>
</view>
</view>
</template>
<script>
import HeaderItem from "@/components/HeaderItem.vue";
import {listLegalCalTypeReq} from "@/api/common";
export default {
name: "cal",
components: {HeaderItem},
data() {
return {
list: []
}
},
methods: {
async getList() {
const {data} = await listLegalCalTypeReq()
this.list = data
},
},
onLoad() {
this.getList()
},
}
</script>
+148
View File
@@ -0,0 +1,148 @@
<template>
<view class="min-height bg-main-light p-20">
<HeaderItem title="法律计算器"/>
<TitleItem :title="title"/>
<view class="mt-25 card flex flex-col justify-start items-start">
<view v-for="(item, index) in list" :key="index"
class="flex justify-start items-center py-15 border-bottom text-25 w-100p">
<text>{{ item.title }}</text>
<template v-if="item.type === 'single'">
<view class="tag"
:class="[list[index].userValue === answer ? 'tag-active' : '']"
@click="list[index].userValue = answer"
v-for="(answer, answerIndex) in JSON.parse(item.answer)" :key="answerIndex">{{ answer }}
</view>
</template>
<template v-else-if="item.type === 'fill'">
<u-input v-model="list[index].userValue" border="bottom"/>
</template>
</view>
<view class="text-25 text-main mt-25">温馨提示:实际情况复杂,计算结果仅供参考</view>
</view>
<view class="mt-25">
<u-button :customStyle="{background: LINEAR(), width: '300rpx', color: 'white'}" shape="circle" @click="doCal">
计算
</u-button>
</view>
<view class="mt-25">
<view v-if="loading" class="p-15 flex justify-center items-center">
<u-loading-icon mode="semicircle" :color="MAIN()"></u-loading-icon>
</view>
<zero-markdown-view v-else :markdown="returnContent"></zero-markdown-view>
</view>
</view>
</template>
<script>
import {listLawLegalCalConfig} from "@/api/common";
import HeaderItem from "@/components/HeaderItem.vue";
import TitleItem from "@/components/TitleItem.vue";
import {LINEAR, MAIN} from "@/config/color";
import {WS_API} from "@/config";
import {getUserInfo} from "@/util/user";
import {sendChatReq} from "@/api/lawOrg";
export default {
name: "calDetail",
components: {TitleItem, HeaderItem},
data() {
return {
list: [],
title: '',
returnContent: '',
loading: false
}
},
methods: {
MAIN() {
return MAIN
},
LINEAR() {
return LINEAR
},
async getList(typeId) {
const {data} = await listLawLegalCalConfig({typeId})
this.list = data.map(item => {
if (item.type === 'single') {
const answer = JSON.parse(item.answer)
item.userValue = answer[0]
} else if (item.type === 'fill') {
item.userValue = ''
} else {
item.userValue = []
}
return item
})
},
doCal() {
this.returnContent = ''
let query = `在广西,我想计算${this.title}`
for (let i = 0; i < this.list.length; i++) {
const item = this.list[i]
if (!item.userValue || item.userValue.length === 0) {
uni.showToast({
title: `${item.title}不能为空`,
icon: 'none'
})
return
}
query += `${item.title}: ${item.userValue};`
}
uni.connectSocket({
url: `${WS_API}/${getUserInfo().uid}`,
success: () => {
this.loading = true
sendChatReq({
query,
user: getUserInfo().uid
}).finally(() => {
uni.closeSocket()
})
}
})
uni.onSocketMessage(res => {
if (res.data === '连接成功') return
this.loading = false
const aiData = JSON.parse(res.data)
if (aiData.answer !== '__END__') this.returnContent += aiData.answer
this.scrollToBottom()
})
},
scrollToBottom() {
setTimeout(() => {
this.$nextTick(() => {
uni.pageScrollTo({
scrollTop: 99999,
duration: 0
})
})
}, 100)
}
},
onLoad({id, title}) {
this.title = title
this.getList(id)
},
}
</script>
<style lang="scss" scoped>
.tag {
border: 1px dashed #999;
padding: 10rpx;
border-radius: 15rpx;
color: #999;
font-size: 25rpx;
width: 60rpx;
display: flex;
align-items: center;
justify-content: center;
margin: 0 10rpx;
}
.tag-active {
color: #3c9cff !important;
border-color: #3c9cff !important;
}
</style>
+47
View File
@@ -0,0 +1,47 @@
<template>
<view class="min-height bg-main-light p-15">
<HeaderItem title="人工咨询"/>
<view class="flex flex-wrap justify-start items-start">
<view class="shadow w-40p bg-white flex flex-col justify-center items-center rounded m-15 p-20" v-for="(item, index) in list"
:key="index" @click="call(item.dictDataCode)">
<u-icon :name="`/userPages/static/phone_${randList[index]}.png`" size="100rpx"/>
<text class="mt-20 text-25">{{ item.dictDataName }}</text>
</view>
</view>
</view>
</template>
<script>
import HeaderItem from "@/components/HeaderItem.vue";
import {dictDataReq} from "@/api/common";
export default {
name: "manual",
components: {HeaderItem},
data() {
return {
list: [],
randList: []
}
},
methods: {
async getList() {
const {data} = await dictDataReq({dictId: 166})
this.randList = []
this.list = data.map(item => {
this.randList.push(uni.$u.random(0, 2))
return item
})
},
call(phoneNumber){
uni.makePhoneCall({
phoneNumber
})
}
},
onLoad() {
this.getList()
},
}
</script>
+119
View File
@@ -0,0 +1,119 @@
<template>
<view>
<view class="flex items-center justify-center" v-if="userInfo" style="padding: 130rpx 0">
<button open-type="chooseAvatar" @chooseavatar="chooseAvatar" class="btn">
<u-avatar :src="`${userInfo.avatar ? userInfo.avatar : ''}`" size="80"/>
</button>
</view>
<view class="p-20">
<u-cell-group :border="false">
<u-cell title="昵称">
<input type="nickname" class="text-right" v-model="userInfo.nickname"
slot="right-icon" @change="changeUsername"/>
</u-cell>
</u-cell-group>
</view>
<view class="p-20">
<u-button @click="save" type="primary" shape="circle">保存修改</u-button>
</view>
<u-action-sheet :actions="genderList" :show="showActionSheet" :closeOnClickAction="true"
round="10" cancelText="取消" @select="selectGender"
@close="showActionSheet = false"/>
</view>
</template>
<script>
import {userInfoReq, userInfoUpdateReq} from "@/api/user";
import {setUserInfo} from "@/util/user";
import {uploadImg} from "@/util";
import {MAIN_API} from "@/config";
export default {
name: "profile",
data() {
return {
cardTypeList: ['充值卡', '月卡', '次卡'],
uri: MAIN_API,
userInfo: {
avatar: null,
nickname: null,
phone: null,
gender: null,
},
genderList: [
{
name: '未知',
value: 0
},
{
name: '男',
value: 1
},
{
name: '女',
value: 2
}
],
showModal: false,
showActionSheet: false,
}
},
methods: {
async getUserInfo() {
const {data} = await userInfoReq()
this.userInfo = data
},
async chooseAvatar({detail}) {
const url = detail.avatarUrl
const {path} = await uploadImg(url)
console.log(path)
this.userInfo.avatar = path
},
selectGender(item) {
this.userInfo.gender = item.value
this.showActionSheet = false
},
changeUsername({detail}) {
const {value} = detail
this.userInfo.nickname = value
},
async save() {
uni.showLoading({
title: '保存中'
})
await userInfoUpdateReq({
avatar: this.userInfo.avatar,
nickname: this.userInfo.nickname,
})
uni.hideLoading()
uni.showToast({
icon: 'success',
title: '已保存',
complete: () => {
setTimeout(() => {
setUserInfo({
header: this.userInfo.avatar,
nickname: this.userInfo.nickname,
})
uni.navigateBack()
}, 1500)
}
})
}
},
async onShow() {
await this.getUserInfo()
}
}
</script>
<style scoped lang="scss">
.btn {
background: none;
}
.btn::after {
border: none;
}
</style>
+108
View File
@@ -0,0 +1,108 @@
<template>
<view class="min-height bg-linear">
<HeaderItem title="企业认证"/>
<view class="rounded-top min-height p-30 bg-gray-light">
<view class="text-25">个人信息</view>
<view class="my-20 card p-30">
<u-form label-width="140rpx">
<u-form-item label="我的行业" required border-bottom @click="showModal = true">
<u-input v-model="userInfo.industry" border="none" placeholder="请选择行业" readonly>
<u-icon
slot="right"
name="arrow-right"
></u-icon>
</u-input>
</u-form-item>
<u-form-item label="企业名称" required border-bottom>
<u-input v-model="userInfo.companyName" border="none" placeholder="请输入单位名"/>
</u-form-item>
<u-form-item label="职位" border-bottom>
<u-input v-model="userInfo.position" border="none" placeholder="请输入职位"/>
</u-form-item>
<u-form-item label="姓名" required>
<u-input v-model="userInfo.realName" border="none" placeholder="请输入姓名"/>
</u-form-item>
</u-form>
</view>
<view class="text-25 mt-20">联系方式</view>
<view class="my-20 card p-30">
<u-form label-width="140rpx">
<u-form-item label="手机号" required border-bottom>
<u-input v-model="userInfo.phone" border="none" placeholder="请输入手机号"/>
</u-form-item>
<u-form-item label="邮箱" border-bottom>
<u-input v-model="userInfo.email" border="none" placeholder="请输入邮箱"/>
</u-form-item>
<u-form-item label="微信号" border-bottom>
<u-input v-model="userInfo.wechatNumber" border="none" placeholder="请输入微信号"/>
</u-form-item>
<u-form-item label="常驻地址" border-bottom>
<u-input v-model="userInfo.liveAddress" border="none" placeholder="请输入常驻地址"/>
</u-form-item>
<u-form-item label="单位地址">
<u-input v-model="userInfo.companyAddress" border="none" placeholder="请输入单位地址"/>
</u-form-item>
</u-form>
</view>
<view class="mt-30">
<u-button type="primary" shape="circle" @click="save">保存</u-button>
</view>
</view>
<u-picker :show="showModal" :columns="[industryList]" @cancel="showModal = false"
@confirm="selectIndustry" key-name="dictDataCode"
/>
</view>
</template>
<script>
import {userInfoReq, userInfoUpdateDataReq, userInfoUpdateReq} from "@/api/user";
import {MAIN_API} from "@/config";
import HeaderItem from "@/components/HeaderItem.vue";
import {dictDataReq} from "@/api/common";
export default {
name: "profile",
components: {HeaderItem},
data() {
return {
uri: MAIN_API,
userInfo: {},
industryList: [],
showModal: false,
showActionSheet: false,
}
},
methods: {
async getIndustryList() {
const {data} = await dictDataReq({dictId: '163'})
this.industryList = data
},
async getUserInfo() {
const {data} = await userInfoReq()
this.userInfo = data
},
selectIndustry({value}) {
this.userInfo.industry = value[0].dictDataCode
this.showModal = false
console.log(this.userInfo)
},
async save() {
if (!this.userInfo.industry) return this.$toast('请选择行业')
if (!this.userInfo.companyName) return this.$toast('请输入企业名称')
if (!this.userInfo.position) return this.$toast('请输入职位')
if (!this.userInfo.realName) return this.$toast('请输入姓名')
if (!this.userInfo.phone) return this.$toast('请输入手机号')
uni.showLoading({
title: '保存中'
})
await userInfoUpdateDataReq(this.userInfo)
uni.hideLoading()
this.$toast('已保存')
}
},
async onShow() {
await this.getUserInfo()
await this.getIndustryList()
}
}
</script>
+67
View File
@@ -0,0 +1,67 @@
<template>
<view class="min-height bg-main-light">
<HeaderItem title="我的专题反馈"/>
<template v-if="list.length">
<view class="card m-25 text-25" v-for="(item, index) in list" :key="index">
<view class="flex justify-start items-center font-bold">
{{ item.title }}
</view>
<view class="flex justify-start items-center mt-15 text-gray">
活动单位: {{ item.company }}
</view>
<view class="flex justify-start items-center mt-15 text-gray">
活动地点: {{ item.address }}
</view>
<view class="flex justify-start items-center mt-15 text-gray">
活动日期: {{ item.date }}
</view>
<template v-if="item.content">
<view class="flex justify-start items-center mt-15 text-gray" :class="[item.showAll ? '' : 'u-line-2']">
活动概览: {{ item.content }}
</view>
<text @click="list[index].showAll = !list[index].showAll" class="text-25 text-main mt-15" v-if="item.showBtn">
{{ item.showAll ? '折叠' : '展开' }}
</text>
</template>
<view class="mt-15" v-if="item.pics">
<u-album :urls="JSON.parse(item.pics)"/>
</view>
<view class="mt-15" v-if="item.video">
<video :src="item.video" style="width: 660rpx; height: 300rpx" class="rounded-sm"></video>
</view>
</view>
</template>
<u-empty v-else icon="/static/empty.png"/>
</view>
</template>
<script>
import HeaderItem from "@/components/HeaderItem.vue";
import {listFeedbackReq} from "@/api/common";
export default {
name: "userFeedback",
components: {HeaderItem},
data() {
return {
list: []
}
},
methods: {
async getList() {
const {data} = await listFeedbackReq()
this.list = data.map(item => {
if (item.content) {
item.showAll = item.content.length < 50
item.showBtn = item.content.length > 50
}
console.log(item)
return item
})
}
},
onLoad() {
this.getList()
},
}
</script>
+44
View File
@@ -0,0 +1,44 @@
<template>
<view class="min-height bg-main-light">
<HeaderItem title="我的法治检查"/>
<template v-if="list.length">
<view class="card m-25 text-25" v-for="(item, index) in list" :key="index">
<view class="flex justify-between items-center">
<text class="font-bold">{{ item.title }}</text>
<u-tag :text="`${item.point}分`" type="primary" shape="circle" size="mini"/>
</view>
<view class="flex justify-start items-center py-15 border-bottom"
v-for="(content, contentIndex) in JSON.parse(item.content)" :key="contentIndex">
<text class="text-gray">{{ content.quest }}:</text>
<text class="ml-10">{{ content.answer }}</text>
</view>
</view>
</template>
<u-empty v-else icon="/static/empty.png"/>
</view>
</template>
<script>
import HeaderItem from "@/components/HeaderItem.vue";
import {listFeedbackReq} from "@/api/common";
import {listLegalOrgCheckContentReq} from "@/api/legalOrgCheck";
export default {
name: "userFeedback",
components: {HeaderItem},
data() {
return {
list: []
}
},
methods: {
async getList() {
const {data} = await listLegalOrgCheckContentReq()
this.list = data
}
},
onLoad() {
this.getList()
},
}
</script>