1
This commit is contained in:
@@ -1 +0,0 @@
|
|||||||
{"containers":[],"config":{}}
|
|
||||||
1
app.js
1
app.js
@@ -1,4 +1,3 @@
|
|||||||
// app.js
|
|
||||||
App({
|
App({
|
||||||
towxml: require('/towxml/index'),
|
towxml: require('/towxml/index'),
|
||||||
globalData: {
|
globalData: {
|
||||||
|
|||||||
11
app.json
11
app.json
@@ -3,10 +3,9 @@
|
|||||||
"pages/system/welcome/index",
|
"pages/system/welcome/index",
|
||||||
"pages/home/index",
|
"pages/home/index",
|
||||||
"pages/test/index",
|
"pages/test/index",
|
||||||
"pages/joinFlow/access/index",
|
|
||||||
"pages/joinFlow/manual/index",
|
|
||||||
"pages/joinFlow/person/index",
|
"pages/joinFlow/person/index",
|
||||||
"pages/expert/index"
|
"pages/expert/index",
|
||||||
|
"pages/chat/index"
|
||||||
],
|
],
|
||||||
"tabBar": {
|
"tabBar": {
|
||||||
"custom": true,
|
"custom": true,
|
||||||
@@ -14,6 +13,9 @@
|
|||||||
{
|
{
|
||||||
"pagePath": "pages/home/index"
|
"pagePath": "pages/home/index"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"pagePath": "pages/chat/index"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"pagePath": "pages/expert/index"
|
"pagePath": "pages/expert/index"
|
||||||
}
|
}
|
||||||
@@ -65,6 +67,7 @@
|
|||||||
"t-cascader": "tdesign-miniprogram/cascader/cascader",
|
"t-cascader": "tdesign-miniprogram/cascader/cascader",
|
||||||
"t-form": "tdesign-miniprogram/form/form",
|
"t-form": "tdesign-miniprogram/form/form",
|
||||||
"t-form-item": "tdesign-miniprogram/form-item/form-item",
|
"t-form-item": "tdesign-miniprogram/form-item/form-item",
|
||||||
"t-divider": "tdesign-miniprogram/divider/divider"
|
"t-divider": "tdesign-miniprogram/divider/divider",
|
||||||
|
"t-loading": "tdesign-miniprogram/loading/loading"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
2
app.scss
2
app.scss
@@ -15,7 +15,9 @@ navigator {
|
|||||||
|
|
||||||
|
|
||||||
page {
|
page {
|
||||||
|
--td-brand-color: rgba(0, 106, 106, 1);
|
||||||
--background: linear-gradient(135deg, rgba(0, 33, 33, 1), rgba(0, 106, 106, 1));
|
--background: linear-gradient(135deg, rgba(0, 33, 33, 1), rgba(0, 106, 106, 1));
|
||||||
|
--area-bottom: calc(130rpx + env(safe-area-inset-bottom));
|
||||||
.t-navbar__capsule::before {
|
.t-navbar__capsule::before {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,11 @@ Component({
|
|||||||
label: '首页',
|
label: '首页',
|
||||||
icon: 'home'
|
icon: 'home'
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "/pages/chat/index",
|
||||||
|
label: 'AI助手',
|
||||||
|
icon: 'chat-bubble'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: "/pages/expert/index",
|
path: "/pages/expert/index",
|
||||||
label: '专家服务',
|
label: '专家服务',
|
||||||
|
|||||||
292
pages/chat/index.js
Normal file
292
pages/chat/index.js
Normal file
@@ -0,0 +1,292 @@
|
|||||||
|
import request, { streamRequest } from "@/utils/request";
|
||||||
|
import { copyText } from "@/utils/common"
|
||||||
|
let outTimer; //输出定时器
|
||||||
|
let outStrList = [];//输出字符串数组
|
||||||
|
const app = getApp()
|
||||||
|
|
||||||
|
let chat_uuid
|
||||||
|
//工具
|
||||||
|
let toolText = ''
|
||||||
|
let toolInfo = {}
|
||||||
|
Page({
|
||||||
|
data: {
|
||||||
|
chatList: [], //会话记录
|
||||||
|
aiStatus: 3,//1表示接口响应中,2表示接口响应完毕,3表示完全输出完毕
|
||||||
|
keyboardBottom: 0, //底部键盘高度
|
||||||
|
scrollTop: 0, //滚动条位置
|
||||||
|
inputText: '',//输入框内容
|
||||||
|
},
|
||||||
|
onLoad() {
|
||||||
|
let str = `您好!我是术极守护AI助手 🤖\n\n我可以为您解答术后康复相关的问题。请注意,我只能提供基于康复指南的一般性建议,如遇紧急情况请立即就医或联系您的主治医生。`
|
||||||
|
let mdResult = app.towxml(str, 'markdown', {
|
||||||
|
base: "www.xxx.com",
|
||||||
|
});
|
||||||
|
let list = [
|
||||||
|
{
|
||||||
|
loading: false,
|
||||||
|
end: true,
|
||||||
|
chat_type: 2,
|
||||||
|
md_content: mdResult,
|
||||||
|
chat_content: str,
|
||||||
|
quick_btn: [
|
||||||
|
{ text: '🩹伤口有轻微渗液怎么办?' },
|
||||||
|
{ text: '🌡️术后轻微发烧正常吗?' },
|
||||||
|
{ text: '🚿什么时候可以洗澡?' },
|
||||||
|
{ text: '🥗饮食需要注意什么?' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
this.setData({
|
||||||
|
chatList: list
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onShow() {
|
||||||
|
this.getTabBar((tabBar) => {
|
||||||
|
tabBar.setData({
|
||||||
|
selected: 'AI助手',
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
//监听键盘弹出
|
||||||
|
bindkeyboardheightchange(event) {
|
||||||
|
let height = event.detail.height
|
||||||
|
let { keyboardBottom } = this.data
|
||||||
|
let scrollTop = 0
|
||||||
|
//获取当前滚动距离
|
||||||
|
const query = wx.createSelectorQuery().in(this)
|
||||||
|
query.select(".silder").scrollOffset()
|
||||||
|
query.exec(function (res) {
|
||||||
|
scrollTop = res[0].scrollTop
|
||||||
|
})
|
||||||
|
this.setData({
|
||||||
|
keyboardBottom: height > 0 ? height - 50 : keyboardBottom,
|
||||||
|
}, () => {
|
||||||
|
if (height > 0) {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.setData({
|
||||||
|
scrollTop: scrollTop + height
|
||||||
|
})
|
||||||
|
}, 300)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
//键盘失去焦点
|
||||||
|
bindkeyboardBlur() {
|
||||||
|
let { scrollTop, keyboardBottom } = this.data
|
||||||
|
let endScrollTop = scrollTop - keyboardBottom
|
||||||
|
this.setData({
|
||||||
|
keyboardBottom: 0
|
||||||
|
}, () => {
|
||||||
|
this.setData({
|
||||||
|
scrollTop: endScrollTop
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
//监听输入框内容
|
||||||
|
changeInput(e) {
|
||||||
|
let value = e.detail.value
|
||||||
|
this.setData({
|
||||||
|
inputText: value
|
||||||
|
})
|
||||||
|
},
|
||||||
|
async handQuick(e) {
|
||||||
|
let { data } = e.currentTarget.dataset
|
||||||
|
this.pushUserTemplate(data.text)
|
||||||
|
this.sendMessage(data.text)
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
// 文字提交发送
|
||||||
|
submitInput() {
|
||||||
|
let { inputText, aiStatus } = this.data
|
||||||
|
if (!inputText.trim() == '' && aiStatus) {
|
||||||
|
console.log('111--');
|
||||||
|
this.pushUserTemplate(inputText)
|
||||||
|
this.sendMessage(inputText)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
//发送聊天
|
||||||
|
async sendMessage(text) {
|
||||||
|
let { chatList, aiStatus } = this.data
|
||||||
|
if (aiStatus == 3) {
|
||||||
|
let that = this
|
||||||
|
//初始化变量
|
||||||
|
toolText = ''
|
||||||
|
toolInfo = {}
|
||||||
|
chat_uuid = String(new Date().getTime())
|
||||||
|
this.setData({
|
||||||
|
aiStatus: 1
|
||||||
|
})
|
||||||
|
//输出
|
||||||
|
this.timerOutput()
|
||||||
|
//请求
|
||||||
|
streamRequest("/ai/chat", {
|
||||||
|
message: text,
|
||||||
|
chat_uuid: chat_uuid,
|
||||||
|
}, this.onChunkReceived).then(() => {
|
||||||
|
console.log('-------------成功-----------');
|
||||||
|
if (this.data.aiStatus != 3) {
|
||||||
|
that.setData({
|
||||||
|
aiStatus: 2
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}).catch(() => {
|
||||||
|
console.log("------失败1---------");
|
||||||
|
that.data.chatList.at(-1).loading = false
|
||||||
|
that.setData({
|
||||||
|
aiStatus: 3,
|
||||||
|
chatList: chatList
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
//填充用户的聊天数据
|
||||||
|
pushUserTemplate(text) {
|
||||||
|
let { chatList } = this.data
|
||||||
|
let userItem = {
|
||||||
|
loading: false,
|
||||||
|
chat_type: 1,
|
||||||
|
con_type: 1,
|
||||||
|
chat_content: text,
|
||||||
|
md_content: '',
|
||||||
|
}
|
||||||
|
let aiItem = {
|
||||||
|
chat_type: 2,
|
||||||
|
chat_content: '',
|
||||||
|
md_content: '',
|
||||||
|
con_type: 1,
|
||||||
|
loading: true,
|
||||||
|
}
|
||||||
|
chatList.push(userItem)
|
||||||
|
|
||||||
|
chatList.push(aiItem)
|
||||||
|
|
||||||
|
//要修改的数据
|
||||||
|
let setData = {
|
||||||
|
chatList,
|
||||||
|
scrollTop: 80000,
|
||||||
|
inputText: ''
|
||||||
|
}
|
||||||
|
this.setData(setData, () => {
|
||||||
|
this.setData({
|
||||||
|
scrollTop: 80000
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
//只填充ai的默认回复
|
||||||
|
pushAiTemplate(text, options = {}) {
|
||||||
|
let { chatList } = this.data
|
||||||
|
let mdResult = app.towxml(text, 'markdown', {
|
||||||
|
base: "www.xxx.com",
|
||||||
|
});
|
||||||
|
let aiItem = {
|
||||||
|
chat_type: 2,
|
||||||
|
chat_content: text,
|
||||||
|
md_content: mdResult,
|
||||||
|
con_type: 1,
|
||||||
|
quick_btn: options.quick_btn || [],
|
||||||
|
...options
|
||||||
|
}
|
||||||
|
chatList.push(aiItem)
|
||||||
|
//要修改的数据
|
||||||
|
let setData = {
|
||||||
|
chatList,
|
||||||
|
scrollTop: 80000,
|
||||||
|
inputText: ''
|
||||||
|
}
|
||||||
|
this.setData(setData, () => {
|
||||||
|
this.setData({
|
||||||
|
scrollTop: 80000
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
//定时器输出
|
||||||
|
timerOutput() {
|
||||||
|
let { chatList } = this.data
|
||||||
|
let that = this
|
||||||
|
clearInterval(outTimer)
|
||||||
|
outStrList = []
|
||||||
|
let lastChat = this.data.chatList.at(-1)
|
||||||
|
//定时
|
||||||
|
outTimer = setInterval(async () => {
|
||||||
|
if ((outStrList.length == 0) && that.data.aiStatus == 2) {
|
||||||
|
clearInterval(outTimer)
|
||||||
|
lastChat.end = true
|
||||||
|
//如果有工具,设置工具对象
|
||||||
|
let text = lastChat.chat_content
|
||||||
|
// 上传AI响应结果
|
||||||
|
if (text) {
|
||||||
|
await request.post("/ai/history/upload", {
|
||||||
|
chat_content: text,
|
||||||
|
chat_uuid: chat_uuid,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
//调用工具
|
||||||
|
if (toolText) { }
|
||||||
|
that.setData({
|
||||||
|
chatList,
|
||||||
|
aiStatus: 3
|
||||||
|
})
|
||||||
|
|
||||||
|
} else if (outStrList.length > 0) {
|
||||||
|
let firstValue = outStrList.shift();
|
||||||
|
lastChat.chat_content += firstValue
|
||||||
|
//转换md
|
||||||
|
let mdResult = app.towxml(lastChat.chat_content, 'markdown', {
|
||||||
|
base: "www.xxx.com",
|
||||||
|
});
|
||||||
|
lastChat.md_content = mdResult
|
||||||
|
lastChat.loading = false
|
||||||
|
that.setData({
|
||||||
|
chatList: chatList,
|
||||||
|
scrollTop: 80000
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, 50)
|
||||||
|
},
|
||||||
|
//流回调
|
||||||
|
onChunkReceived(data) {
|
||||||
|
data.forEach((item) => {
|
||||||
|
let value = item?.choices[0].delta.content ?? ''
|
||||||
|
let call = item?.choices[0].delta.tool_calls
|
||||||
|
//储存tool的id和名称
|
||||||
|
if (call) {
|
||||||
|
if (call[0].id) {
|
||||||
|
toolInfo.tool_call_id = call[0].id
|
||||||
|
toolInfo.name = call[0].function.name
|
||||||
|
}
|
||||||
|
let tool = call[0].function.arguments ?? ''
|
||||||
|
toolText += tool
|
||||||
|
}
|
||||||
|
if (value) {
|
||||||
|
outStrList.push(value)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
//停止
|
||||||
|
async stopMessage() {
|
||||||
|
clearInterval(outTimer)
|
||||||
|
let lastChat = this.data.chatList.at(-1)
|
||||||
|
lastChat.chat_status = 2
|
||||||
|
this.setData({
|
||||||
|
aiStatus: 3,
|
||||||
|
chatList: this.data.chatList
|
||||||
|
})
|
||||||
|
await request.post("/ai/history/upload", {
|
||||||
|
chat_content: lastChat.chat_content || 'nocontent',
|
||||||
|
chat_status: 2,
|
||||||
|
chat_uuid: chat_uuid
|
||||||
|
})
|
||||||
|
},
|
||||||
|
//复制文字
|
||||||
|
copy(e) {
|
||||||
|
let { content, chat_content } = e.currentTarget.dataset.text
|
||||||
|
console.log(e);
|
||||||
|
if (!content) {
|
||||||
|
content = chat_content
|
||||||
|
}
|
||||||
|
copyText(content)
|
||||||
|
},
|
||||||
|
})
|
||||||
6
pages/chat/index.json
Normal file
6
pages/chat/index.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"usingComponents": {
|
||||||
|
"towxml": "/towxml/towxml"
|
||||||
|
},
|
||||||
|
"navigationStyle": "custom"
|
||||||
|
}
|
||||||
179
pages/chat/index.scss
Normal file
179
pages/chat/index.scss
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
@import "./makedown.scss";
|
||||||
|
|
||||||
|
.c-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100vh;
|
||||||
|
padding-bottom: var(--area-bottom);
|
||||||
|
|
||||||
|
.t-navbar__content {
|
||||||
|
backdrop-filter: blur(18px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.silder {
|
||||||
|
overflow: auto;
|
||||||
|
flex: 1;
|
||||||
|
padding: 30rpx 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
.chat-item {
|
||||||
|
padding: 10rpx 30rpx;
|
||||||
|
|
||||||
|
&+.chat-item {
|
||||||
|
margin-top: 30rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lawyer-info {
|
||||||
|
margin-bottom: 20rpx;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
|
||||||
|
image {
|
||||||
|
width: 50rpx;
|
||||||
|
height: 50rpx;
|
||||||
|
border-radius: 50%;
|
||||||
|
margin-right: 10rpx;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-image {
|
||||||
|
width: 250rpx;
|
||||||
|
height: 250rpx;
|
||||||
|
border-radius: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-message {
|
||||||
|
max-width: calc(100% - 100rpx);
|
||||||
|
min-height: 60rpx;
|
||||||
|
width: fit-content;
|
||||||
|
padding: 20rpx;
|
||||||
|
border-radius: 10rpx;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.loading {
|
||||||
|
height: 40rpx;
|
||||||
|
width: 40rpx;
|
||||||
|
border-radius: 50%;
|
||||||
|
box-shadow: inset 0 0 0 var(--td-brand-color);
|
||||||
|
animation: load 2s linear infinite alternate;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stop-tip {
|
||||||
|
margin-top: 20rpx;
|
||||||
|
font-size: 0.64rem;
|
||||||
|
color: var(--text-3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.m-footer {
|
||||||
|
margin-top: 10rpx;
|
||||||
|
|
||||||
|
.tip {
|
||||||
|
@extend .stop-tip;
|
||||||
|
margin-top: 0;
|
||||||
|
opacity: 0.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sound-icon {
|
||||||
|
color: var(--text-2);
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.quick-warpper {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
gap: 30rpx;
|
||||||
|
margin-top: 20rpx;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
|
||||||
|
.quick-item {
|
||||||
|
background-color: white;
|
||||||
|
padding: 10rpx 20rpx;
|
||||||
|
border-radius: 50rpx;
|
||||||
|
border: 1px solid #dfdddd;
|
||||||
|
|
||||||
|
&.color {
|
||||||
|
color: white;
|
||||||
|
border-color: transparent;
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-msg {
|
||||||
|
.chat-message {
|
||||||
|
background-color: white;
|
||||||
|
border-radius: 20rpx 30rpx 30rpx 10rpx;
|
||||||
|
box-shadow: 0 0 15rpx #e2e2e2;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-msg {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-end;
|
||||||
|
|
||||||
|
.chat-message {
|
||||||
|
background-color: var(--td-brand-color);
|
||||||
|
color: white;
|
||||||
|
border-radius: 30rpx 30rpx 0 30rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.bottom-position {
|
||||||
|
margin: 0 30rpx;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
//输入框
|
||||||
|
.input-warpper {
|
||||||
|
box-shadow: 0 0 15rpx #e2e2e2;
|
||||||
|
padding: 20rpx 30rpx;
|
||||||
|
background-color: white;
|
||||||
|
border-radius: 50rpx;
|
||||||
|
|
||||||
|
input {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.push-btn {
|
||||||
|
border-radius: 50%;
|
||||||
|
width: 65rpx;
|
||||||
|
height: 65rpx;
|
||||||
|
color: var(--text-3);
|
||||||
|
transition: opacity 0.3s;
|
||||||
|
|
||||||
|
&.active-push {
|
||||||
|
background-color: var(--td-brand-color);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.stop-btn {
|
||||||
|
font-size: 65rpx;
|
||||||
|
color: var(--td-brand-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//占位
|
||||||
|
.empty {
|
||||||
|
transition: height 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
//ai响应loading
|
||||||
|
@keyframes load {
|
||||||
|
0% {
|
||||||
|
box-shadow: inset -20rpx 40rpx 0 var(--td-brand-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
box-shadow: inset 20rpx -40rpx 0 var(--td-brand-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
103
pages/chat/index.wxml
Normal file
103
pages/chat/index.wxml
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
<page-meta root-font-size="system"></page-meta>
|
||||||
|
|
||||||
|
<view class="bg-gradient c-container">
|
||||||
|
<t-navbar class="custom-top-navbar"
|
||||||
|
fixed="{{false}}"
|
||||||
|
title="AI健康管家">
|
||||||
|
</t-navbar>
|
||||||
|
<scroll-view class="silder"
|
||||||
|
scroll-top="{{scrollTop}}"
|
||||||
|
scroll-y>
|
||||||
|
<view class="chat-item {{item.chat_type == 1 ? 'user-msg' : 'ai-msg'}}"
|
||||||
|
id="chat-${{index}}"
|
||||||
|
wx:for="{{chatList}}"
|
||||||
|
wx:key="index">
|
||||||
|
<view class="lawyer-info flex-align"
|
||||||
|
wx:if="{{item.chat_type !=1}}">
|
||||||
|
<text>AI助手</text>
|
||||||
|
</view>
|
||||||
|
<!-- 显示图片格式 -->
|
||||||
|
<view wx:if="{{item.con_type == 2}}">
|
||||||
|
<image src="{{item.chat_content}}"
|
||||||
|
class="chat-image"
|
||||||
|
data-url="{{item.chat_content}}"
|
||||||
|
bind:tap="viewImg"
|
||||||
|
mode="aspectFill" />
|
||||||
|
</view>
|
||||||
|
<view class="chat-message "
|
||||||
|
wx:else>
|
||||||
|
<view class="loading"
|
||||||
|
wx:if="{{item.loading}}"></view>
|
||||||
|
<view wx:elif="{{item.tool}}">
|
||||||
|
{{item.tool}}
|
||||||
|
</view>
|
||||||
|
<view wx:elif="{{item.chat_type == 1}}">
|
||||||
|
{{item.chat_content}}
|
||||||
|
</view>
|
||||||
|
<towxml wx:elif="{{item.chat_type == 2}}"
|
||||||
|
data-text="{{item}}"
|
||||||
|
bind:longpress="copy"
|
||||||
|
nodes="{{item.md_content}}" />
|
||||||
|
<!-- 底部功能 -->
|
||||||
|
<view wx:if="{{item.chat_status == 2}}"
|
||||||
|
class="stop-tip">
|
||||||
|
(已停止)
|
||||||
|
</view>
|
||||||
|
<view class="m-footer flex-between"
|
||||||
|
wx:elif="{{item.end}}">
|
||||||
|
<view class="tip">
|
||||||
|
AI助手仅提供基于康复指南的一般性建议,不构成医疗诊断。如遇紧急情况请立即就医
|
||||||
|
</view>
|
||||||
|
<view class="flex-align">
|
||||||
|
<t-icon name="file-copy"
|
||||||
|
class="sound-icon"
|
||||||
|
data-text="{{item}}"
|
||||||
|
bind:tap="copy" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<!-- 快捷按钮 -->
|
||||||
|
<view class="quick-warpper"
|
||||||
|
wx:if="{{item.quick_btn.length > 0 && item.end}}">
|
||||||
|
<view class="quick-item quick-{{quick.type}} {{quick.color ? 'color' : ''}}"
|
||||||
|
wx:for="{{item.quick_btn}}"
|
||||||
|
style="background-color: {{quick.color}};"
|
||||||
|
wx:for-item="quick"
|
||||||
|
wx:key="index"
|
||||||
|
bind:tap="handQuick"
|
||||||
|
data-parent="{{item}}"
|
||||||
|
data-data="{{quick}}">
|
||||||
|
{{quick.text}}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
|
||||||
|
<!-- 底部按钮 -->
|
||||||
|
<view class="bottom-position">
|
||||||
|
<!-- 输入框 -->
|
||||||
|
<view class="input-warpper flex-align">
|
||||||
|
<input placeholder="有什么问题尽管问我"
|
||||||
|
bindblur="bindkeyboardBlur"
|
||||||
|
bindinput="changeInput"
|
||||||
|
bindconfirm="submitInput"
|
||||||
|
value="{{inputText}}"
|
||||||
|
hold-keyboard="{{false}}"
|
||||||
|
adjust-position="{{false}}"
|
||||||
|
bindkeyboardheightchange="bindkeyboardheightchange" />
|
||||||
|
|
||||||
|
<view class="push-btn flex-center {{inputText !='' ? 'active-push' : ''}} "
|
||||||
|
wx:if="{{aiStatus==3}}"
|
||||||
|
bind:tap="submitInput">
|
||||||
|
<t-icon name="send-filled" />
|
||||||
|
</view>
|
||||||
|
<t-icon name="stop-circle-filled"
|
||||||
|
class="stop-btn"
|
||||||
|
bind:tap="stopMessage"
|
||||||
|
wx:else />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<!-- 占位撑高 -->
|
||||||
|
<view style="height: {{keyboardBottom}}px;"
|
||||||
|
class="empty"></view>
|
||||||
|
</view>
|
||||||
17
pages/chat/makedown.scss
Normal file
17
pages/chat/makedown.scss
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
.h2w__main,
|
||||||
|
.h2w__p {
|
||||||
|
padding: 0 !important;
|
||||||
|
margin: 0 !important;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.h2w__li {
|
||||||
|
margin-top: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.h2w__h3 {
|
||||||
|
font-size: 32rpx !important;
|
||||||
|
margin-top: 20rpx !important;
|
||||||
|
}
|
||||||
15
pages/chat/read.md
Normal file
15
pages/chat/read.md
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
聊天列表类型
|
||||||
|
``` typescript
|
||||||
|
interface ChatType{
|
||||||
|
loading: boolean, // 是否开始响应
|
||||||
|
end:boolean,//响应输出完成
|
||||||
|
chat_type: 1 | 2, // 1用户,2ai普通响应
|
||||||
|
chat_content: string, //文本内容
|
||||||
|
md_content: string, //md格式
|
||||||
|
con_type:1, //消息类型,1文本,2图片
|
||||||
|
tool:string, //用工具时的默认内容,为空代表不是工具
|
||||||
|
chat_status?:number, //2停止
|
||||||
|
quick_btn:[], //快捷菜单按钮,为空不显示
|
||||||
|
drugList:[],//药品信息,只用来设置提醒
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -1,9 +1,77 @@
|
|||||||
|
import request from "@/utils/request"
|
||||||
|
|
||||||
|
const app = getApp()
|
||||||
Page({
|
Page({
|
||||||
|
data: {
|
||||||
|
list: [
|
||||||
|
{
|
||||||
|
s: "李",
|
||||||
|
name: "李医生",
|
||||||
|
title: "主任医师 · 骨科专家",
|
||||||
|
desc: "20年临床经验"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
s: "王",
|
||||||
|
name: "王医生",
|
||||||
|
title: "副主任医师 · 康复医学",
|
||||||
|
desc: "15年临床经验"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
s: "张",
|
||||||
|
name: "张护士长",
|
||||||
|
title: "主管护师 · 伤口护理",
|
||||||
|
desc: "18年护理经验"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
count: 0
|
||||||
|
},
|
||||||
onShow() {
|
onShow() {
|
||||||
|
let userInfo = app.globalData.userInfo
|
||||||
|
this.setData({
|
||||||
|
count: userInfo.consult_remains
|
||||||
|
})
|
||||||
this.getTabBar((tabBar) => {
|
this.getTabBar((tabBar) => {
|
||||||
tabBar.setData({
|
tabBar.setData({
|
||||||
selected: '专家服务',
|
selected: '专家服务',
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
async onPlay() {
|
||||||
|
if (this.data.count <= 0) {
|
||||||
|
wx.showToast({
|
||||||
|
title: '免费次数已用完',
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 2. 弹窗确认
|
||||||
|
wx.showModal({
|
||||||
|
title: '拨打专家热线',
|
||||||
|
content: '确认拨打专家咨询电话吗?本次咨询将使用1次免费机会',
|
||||||
|
success: async (res) => {
|
||||||
|
if (res.confirm) {
|
||||||
|
try {
|
||||||
|
wx.showLoading({ title: '正在呼叫...', mask: true });
|
||||||
|
const info = await request.get("/expert/phone");
|
||||||
|
this.setData({
|
||||||
|
count: this.data.count - 1
|
||||||
|
});
|
||||||
|
wx.hideLoading();
|
||||||
|
|
||||||
|
// 5. 吊起拨号盘
|
||||||
|
if (info && info.expert_phone) {
|
||||||
|
wx.makePhoneCall({
|
||||||
|
phoneNumber: info.expert_phone,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
wx.showToast({ title: '暂无专家电话', icon: 'none' });
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
wx.hideLoading();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
page {
|
page {
|
||||||
background-color: rgba(247, 249, 252, 1);
|
background-color: rgba(247, 249, 252, 1);
|
||||||
|
padding-bottom: 200rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.head {
|
.head {
|
||||||
@@ -47,11 +48,175 @@ page {
|
|||||||
color: rgba(255, 255, 255, 0.8);
|
color: rgba(255, 255, 255, 0.8);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn {
|
.btn {
|
||||||
padding: 50rpx 0;
|
padding: 50rpx 0;
|
||||||
background-color: rgba(29, 120, 116, 1);
|
background-color: rgba(29, 120, 116, 1);
|
||||||
}
|
}
|
||||||
.c-2{
|
|
||||||
|
|
||||||
|
.service-card {
|
||||||
|
width: 100%;
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 16px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.05);
|
||||||
|
margin-top: 30rpx;
|
||||||
|
|
||||||
|
.flex-align {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
.icon {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
background-color: #f0f5f0; // 图标背景色
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
margin-top: 12px;
|
||||||
|
|
||||||
|
.row {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-top: 6px;
|
||||||
|
|
||||||
|
.label {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.time {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #18a74f; // 绿色
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.status {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: 12px;
|
||||||
|
|
||||||
|
.dot {
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: #18a74f;
|
||||||
|
margin-right: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #18a74f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.emergency-card {
|
||||||
|
background: rgba(255, 235, 238, 1);
|
||||||
|
border-radius: 16rpx;
|
||||||
|
padding: 32rpx;
|
||||||
|
margin-top: 30rpx;
|
||||||
|
gap: 30rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
--color: rgba(198, 40, 40, 1);
|
||||||
|
color: var(--color);
|
||||||
|
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
width: 90rpx;
|
||||||
|
aspect-ratio: 1;
|
||||||
|
background-color: rgba(186, 26, 26, 0.15);
|
||||||
|
border-radius: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.t-1 {
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 34rpx;
|
||||||
|
margin-bottom: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.num {
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 40rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item {
|
||||||
|
font-size: 28rpx;
|
||||||
|
line-height: 60rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 20rpx;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
width: 8rpx;
|
||||||
|
height: 8rpx;
|
||||||
|
background-color: var(--color);
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.service {
|
||||||
|
background-color: white;
|
||||||
|
--color: black;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
background-color: rgba(0, 106, 106, 0.1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.express {
|
||||||
|
background-color: white;
|
||||||
|
padding: 30rpx;
|
||||||
|
border-radius: 16rpx;
|
||||||
|
margin-top: 30rpx;
|
||||||
|
|
||||||
|
.item {
|
||||||
|
gap: 30rpx;
|
||||||
|
margin-top: 40rpx;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
width: 100rpx;
|
||||||
|
aspect-ratio: 1;
|
||||||
|
border-radius: 50%;
|
||||||
|
color: white;
|
||||||
|
font-weight: 700;
|
||||||
|
background: linear-gradient(rgba(29, 120, 116, 1), rgba(46, 139, 139, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
.t-1 {
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.t-2 {
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: rgba(69, 70, 78, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.t-3 {
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: rgba(69, 70, 78, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -14,21 +14,91 @@
|
|||||||
<t-icon name="check-circle" />
|
<t-icon name="check-circle" />
|
||||||
可咨询次数
|
可咨询次数
|
||||||
</view>
|
</view>
|
||||||
<view class="num">3</view>
|
<view class="num">{{count}}</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="tip">本月剩余 3 次免费咨询机会</view>
|
<view class="tip">本月剩余 {{count}} 次免费咨询机会</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<t-button block
|
<t-button block
|
||||||
theme="primary"
|
theme="primary"
|
||||||
class="btn"
|
class="btn"
|
||||||
icon="call-1">
|
icon="call-1"
|
||||||
|
bind:tap="onPlay">
|
||||||
一键拨打专家电话
|
一键拨打专家电话
|
||||||
</t-button>
|
</t-button>
|
||||||
|
|
||||||
<view class="c-2 flex-align">
|
<view class="service-card">
|
||||||
|
<view class="header flex-align">
|
||||||
<view class="icon">
|
<view class="icon">
|
||||||
<t-icon name="time" />
|
<t-icon name="time" />
|
||||||
</view>
|
</view>
|
||||||
|
<view class="title">服务时间</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="content">
|
||||||
|
<view class="row">
|
||||||
|
<view class="label">工作日</view>
|
||||||
|
<view class="time">09:00 - 21:00</view>
|
||||||
|
</view>
|
||||||
|
<view class="row">
|
||||||
|
<view class="label">周末及节假日</view>
|
||||||
|
<view class="time">10:00 - 18:00</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="status">
|
||||||
|
<view class="dot"></view>
|
||||||
|
<view class="text">当前服务中</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="emergency-card">
|
||||||
|
<view class="icon flex-center">
|
||||||
|
<t-icon name="error-triangle" />
|
||||||
|
</view>
|
||||||
|
<view style="flex: 1;">
|
||||||
|
<view class="t-1">紧急情况处理</view>
|
||||||
|
<view>如遇以下紧急情况,请立即拨打</view>
|
||||||
|
<view style="margin-bottom: 20rpx;"><text class="num">120</text> 或前往急诊</view>
|
||||||
|
|
||||||
|
<view class="list">
|
||||||
|
<view class="item">大量出血或伤口裂开</view>
|
||||||
|
<view class="item">高热不退(体温≥39°C)</view>
|
||||||
|
<view class="item">剧烈疼痛无法缓解</view>
|
||||||
|
<view class="item">呼吸困难或胸痛</view>
|
||||||
|
<view class="item">意识模糊或昏迷</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="emergency-card service">
|
||||||
|
<view class="icon flex-center">
|
||||||
|
<t-icon name="info-circle" />
|
||||||
|
</view>
|
||||||
|
<view style="flex: 1;">
|
||||||
|
<view class="t-1">服务说明</view>
|
||||||
|
|
||||||
|
<view class="list">
|
||||||
|
<view class="item">每次通话时长不超过15分钟</view>
|
||||||
|
<view class="item">专家会根据您的情况提供专业建议</view>
|
||||||
|
<view class="item">复杂问题可能需要您到院面诊</view>
|
||||||
|
<view class="item">建议提前准备好相关检查报告</view>
|
||||||
|
<view class="item">咨询记录会同步到您的康复档案</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="express">
|
||||||
|
<view style="font-weight: 700;">专家团队</view>
|
||||||
|
<view class="item flex-align"
|
||||||
|
wx:for="{{list}}"
|
||||||
|
wx:key="index">
|
||||||
|
<view class="icon flex-center">{{item.s}}</view>
|
||||||
|
<view>
|
||||||
|
<view class="t-1">{{item.name}}</view>
|
||||||
|
<view class="t-2">{{item.title}}</view>
|
||||||
|
<view class="t-3">{{item.desc}}</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -1,7 +1,15 @@
|
|||||||
|
import request from "@/utils/request"
|
||||||
Page({
|
Page({
|
||||||
|
|
||||||
data: {
|
data: {
|
||||||
|
detail: {
|
||||||
|
overview: {},
|
||||||
|
tasks: [{}, {}, {}],
|
||||||
|
},
|
||||||
|
loading: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
onLoad() {
|
||||||
|
this.init()
|
||||||
},
|
},
|
||||||
|
|
||||||
onShow() {
|
onShow() {
|
||||||
@@ -10,5 +18,31 @@ Page({
|
|||||||
selected: '首页',
|
selected: '首页',
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
async init() {
|
||||||
|
let res = await request.get("/home")
|
||||||
|
this.setData({
|
||||||
|
detail: res,
|
||||||
|
loading: false,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
//手动标记是否完成
|
||||||
|
handDone(e) {
|
||||||
|
const { data } = e.currentTarget.dataset;
|
||||||
|
const newTasks = this.data.detail.tasks.map(v => {
|
||||||
|
if (v.task_id == data.task_id) {
|
||||||
|
// 如果当前是 1 则变为 0,如果是 0 则变为 1
|
||||||
|
return { ...v, is_completed: v.is_completed == 1 ? 0 : 1 };
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
});
|
||||||
|
request.post("/home/task-record", {
|
||||||
|
...data,
|
||||||
|
is_completed: data.is_completed == 1 ? 0 : 1
|
||||||
|
})
|
||||||
|
this.setData({
|
||||||
|
'detail.tasks': newTasks
|
||||||
|
});
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
page {
|
page {
|
||||||
background-color: rgba(247, 249, 252, 1);
|
background-color: rgba(247, 249, 252, 1);
|
||||||
|
padding-bottom: 160rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.header {
|
.header {
|
||||||
@@ -78,11 +79,15 @@ page {
|
|||||||
width: 90rpx;
|
width: 90rpx;
|
||||||
aspect-ratio: 1;
|
aspect-ratio: 1;
|
||||||
border-radius: 20rpx;
|
border-radius: 20rpx;
|
||||||
background-color: var(--color);
|
background-color: var(--back);
|
||||||
color: rgba(99, 63, 0, 1);
|
color: rgba(99, 63, 0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
|
flex: 1;
|
||||||
|
--td-tag-default-light-color: var(--back);
|
||||||
|
--td-tag-default-font-color: var(--color);
|
||||||
|
|
||||||
.time {
|
.time {
|
||||||
margin-left: 20rpx;
|
margin-left: 20rpx;
|
||||||
color: rgba(69, 70, 78, 1);
|
color: rgba(69, 70, 78, 1);
|
||||||
|
|||||||
@@ -1,22 +1,25 @@
|
|||||||
|
<wxs src="/utils/wxs/comment.wxs"
|
||||||
|
module="utils"></wxs>
|
||||||
|
|
||||||
<view class="header">
|
<view class="header">
|
||||||
<t-navbar class="fixed-nav"
|
<t-navbar class="fixed-nav"
|
||||||
fixed="{{false}}" />
|
fixed="{{false}}" />
|
||||||
<view class="h-1">
|
<view class="h-1">
|
||||||
<view class="left">
|
<view class="left">
|
||||||
<view class="t-1">术后第 2 天</view>
|
<view class="t-1">术后第 {{detail.overview.postoperative_day || 0}} 天</view>
|
||||||
<view class="t-2">康复进行中</view>
|
<view class="t-2">{{detail.overview.status_text}}</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="right flex-column-center ">
|
<view class="right flex-column-center ">
|
||||||
<view class="d">2</view>
|
<view class="d">{{detail.overview.postoperative_day || 0}} </view>
|
||||||
<view class="c">DAYS</view>
|
<view class="c">DAYS</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="h-2">
|
<view class="h-2">
|
||||||
<view class="flex-between title">
|
<view class="flex-between title">
|
||||||
<view>今日任务完成度</view>
|
<view>今日任务完成度</view>
|
||||||
<view class="num">0/5</view>
|
<view class="num">{{taskUtils.getDoneCount(detail.tasks)}}/{{detail.overview.total_task_count}}</view>
|
||||||
</view>
|
</view>
|
||||||
<t-progress percentage="80"
|
<t-progress percentage="{{taskUtils.getDoneCount(detail.tasks) / detail.overview.total_task_count * 100}}"
|
||||||
color="{{ ['white', 'white'] }}"
|
color="{{ ['white', 'white'] }}"
|
||||||
track-color="rgba(255, 255, 255, 0.2)"
|
track-color="rgba(255, 255, 255, 0.2)"
|
||||||
label="" />
|
label="" />
|
||||||
@@ -25,20 +28,31 @@
|
|||||||
|
|
||||||
<view class="list">
|
<view class="list">
|
||||||
<view class="item flex-align"
|
<view class="item flex-align"
|
||||||
wx:for="{{5}}"
|
style="--color:{{item.label_color}};--back:{{utils.getLightColor(item.label_color)}}"
|
||||||
|
wx:for="{{detail.tasks}}"
|
||||||
wx:key="index">
|
wx:key="index">
|
||||||
|
<t-skeleton loading="{{loading}}"
|
||||||
|
rowCol="{{[{ size: '90rpx' }]}}">
|
||||||
<view class="icon flex-center">
|
<view class="icon flex-center">
|
||||||
<t-icon name="apple" />
|
<t-icon name="{{item.pill}}" />
|
||||||
</view>
|
</view>
|
||||||
|
</t-skeleton>
|
||||||
|
|
||||||
<view class="content">
|
<view class="content">
|
||||||
|
<t-skeleton loading="{{loading}}"
|
||||||
|
theme="paragraph">
|
||||||
<view class="flex-align">
|
<view class="flex-align">
|
||||||
<t-tag variant="light"
|
<t-tag variant="light">{{item.category_label}}</t-tag>
|
||||||
theme="success">用药</t-tag>
|
<view class="time">{{item.time_label}}</view>
|
||||||
<view class="time">08:00</view>
|
|
||||||
</view>
|
</view>
|
||||||
<view class="title">服用抗生素</view>
|
<view class="title">{{item.title}}</view>
|
||||||
<view class="desc">头孢类抗生素,饭后服用</view>
|
<view class="desc">{{item.content}}</view>
|
||||||
<button class="btn">标记完成</button>
|
<button class="btn {{item.is_completed == 1 ? 'active' : ''}}"
|
||||||
|
bind:tap="handDone"
|
||||||
|
data-data="{{item}}">
|
||||||
|
{{item.is_completed == 0 ? '标记完成' : '已完成' }}
|
||||||
|
</button>
|
||||||
|
</t-skeleton>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -48,3 +62,21 @@
|
|||||||
<view class="text"> 请按时完成康复任务,如有任何不适请及时联系医护人员</view>
|
<view class="text"> 请按时完成康复任务,如有任何不适请及时联系医护人员</view>
|
||||||
</view>
|
</view>
|
||||||
<view style="height: 30rpx;"></view>
|
<view style="height: 30rpx;"></view>
|
||||||
|
|
||||||
|
|
||||||
|
<wxs module="taskUtils">
|
||||||
|
var getDoneCount = function (tasks) {
|
||||||
|
if (!tasks || !tasks.length) return 0;
|
||||||
|
var count = 0;
|
||||||
|
for (var i = 0; i < tasks.length; i++) {
|
||||||
|
if (tasks[i].is_completed == 1 || tasks[i].is_completed === true) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
getDoneCount: getDoneCount
|
||||||
|
};
|
||||||
|
</wxs>
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
// pages/auth/access/index.js
|
|
||||||
Page({
|
|
||||||
|
|
||||||
data: {
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
handClick(e) {
|
|
||||||
let { type } = e.currentTarget.dataset
|
|
||||||
//拍照
|
|
||||||
if (type == 1) {
|
|
||||||
wx.scanCode({
|
|
||||||
onlyFromCamera: true,
|
|
||||||
scanType: ['qrCode'],
|
|
||||||
success(res) {
|
|
||||||
console.log(res);
|
|
||||||
},
|
|
||||||
fail(err) {
|
|
||||||
wx.showToast({
|
|
||||||
title: '扫码失败',
|
|
||||||
icon: 'none'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
wx.navigateTo({
|
|
||||||
url: "/pages/joinFlow/manual/index",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
{
|
|
||||||
"usingComponents": {},
|
|
||||||
"navigationStyle": "custom"
|
|
||||||
}
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
page {
|
|
||||||
height: 100vh;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.banner {
|
|
||||||
height: 400rpx;
|
|
||||||
background-image: var(--background);
|
|
||||||
padding: 30rpx;
|
|
||||||
|
|
||||||
.text-1 {
|
|
||||||
color: white;
|
|
||||||
font-size: 60rpx;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.text-2 {
|
|
||||||
font-size: 28rpx;
|
|
||||||
color: rgba(255, 255, 255, 0.8);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.content {
|
|
||||||
flex: 1;
|
|
||||||
background-color: white;
|
|
||||||
transform: translateY(-20rpx);
|
|
||||||
border-radius: 30rpx 30rpx 0 0;
|
|
||||||
padding: 80rpx 30rpx 30rpx;
|
|
||||||
|
|
||||||
.text-1 {
|
|
||||||
text-align: center;
|
|
||||||
font-weight: 700;
|
|
||||||
font-size: 45rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.text-2 {
|
|
||||||
font-size: 28rpx;
|
|
||||||
text-align: center;
|
|
||||||
color: rgba(69, 70, 78, 1);
|
|
||||||
margin-top: 20rpx;
|
|
||||||
margin-bottom: 60rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.item {
|
|
||||||
box-shadow: 0 4rpx 12rpx rgba(11, 27, 61, 0.14);
|
|
||||||
padding: 30rpx;
|
|
||||||
border-radius: 30rpx;
|
|
||||||
gap: 30rpx;
|
|
||||||
margin-bottom: 60rpx;
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
width: 90rpx;
|
|
||||||
aspect-ratio: 1;
|
|
||||||
background-color: rgba(0, 106, 106, 0.1);
|
|
||||||
font-size: 50rpx;
|
|
||||||
border-radius: 20rpx;
|
|
||||||
color: rgba(46, 139, 87, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.t-1 {
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.t-2 {
|
|
||||||
margin-top: 10rpx;
|
|
||||||
font-size: 24rpx;
|
|
||||||
color: rgba(69, 70, 78, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.tip {
|
|
||||||
background-color: rgba(255, 221, 180, 1);
|
|
||||||
padding: 30rpx;
|
|
||||||
border-radius: 20rpx;
|
|
||||||
color: rgba(99, 63, 0, 1);
|
|
||||||
font-size: 28rpx;
|
|
||||||
line-height: 44rpx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
<view class="banner">
|
|
||||||
<t-navbar t-class="fixed-nav"
|
|
||||||
fixed="{{false}}" />
|
|
||||||
<view class="info">
|
|
||||||
<view class="text-1">术极守护</view>
|
|
||||||
<view class="text-2">您的贴身康复管家</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="content">
|
|
||||||
<view class="text-1">开始使用</view>
|
|
||||||
<view class="text-2">请选择康复计划接入方式</view>
|
|
||||||
<view class="item flex-align"
|
|
||||||
bind:tap="handClick"
|
|
||||||
data-type="1">
|
|
||||||
<view class="icon flex-center">
|
|
||||||
<t-icon name="qrcode" />
|
|
||||||
</view>
|
|
||||||
<view>
|
|
||||||
<view class="t-1">扫码接入</view>
|
|
||||||
<view class="t-2">扫描医护人员提供的二维码</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view class="item flex-align"
|
|
||||||
bind:tap="handClick"
|
|
||||||
data-type="2">
|
|
||||||
<view class="icon flex-center">
|
|
||||||
<t-icon name="search" />
|
|
||||||
</view>
|
|
||||||
<view>
|
|
||||||
<view class="t-1">手动选择</view>
|
|
||||||
<view class="t-2">搜索医院、科室、手术名称</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="tip">
|
|
||||||
<view>💡 温馨提示:</view>
|
|
||||||
<view>首次使用需要录入基本信息,请准备好您的手术相关资料</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
Page({
|
|
||||||
data: {
|
|
||||||
formData: {
|
|
||||||
hospital: "",
|
|
||||||
department: ""
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onInputChange(e) {
|
|
||||||
console.log("dsds");
|
|
||||||
const {field} = e.currentTarget.dataset;
|
|
||||||
this.setData({
|
|
||||||
[`formData.${field}`]: e.detail.value,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
onSubmit() {
|
|
||||||
let {formData} = this.data
|
|
||||||
let errorText = ""
|
|
||||||
if (!formData.hospital.trim()) {
|
|
||||||
errorText = "请填写医院名称"
|
|
||||||
}
|
|
||||||
if (!formData.department.trim()) {
|
|
||||||
errorText = "请填写科室名称"
|
|
||||||
}
|
|
||||||
if (errorText) {
|
|
||||||
wx.showToast({
|
|
||||||
title: errorText,
|
|
||||||
icon: "none"
|
|
||||||
})
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
wx.navigateTo({
|
|
||||||
url: "/pages/joinFlow/person/index"
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
{
|
|
||||||
"usingComponents": {},
|
|
||||||
"navigationStyle": "custom"
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
.content {
|
|
||||||
margin-top: 60rpx;
|
|
||||||
|
|
||||||
.btn {
|
|
||||||
margin-top: 60rpx;
|
|
||||||
padding: 40rpx 30rpx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
<t-navbar title="选择康复计划"
|
|
||||||
left-arrow
|
|
||||||
fixed="{{false}}" />
|
|
||||||
|
|
||||||
<view class="content">
|
|
||||||
<t-input value="{{formData.hospital}}"
|
|
||||||
borderless
|
|
||||||
label="医院"
|
|
||||||
placeholder="请输入医院名称"
|
|
||||||
bind:change="onInputChange"
|
|
||||||
data-field="hospital" />
|
|
||||||
<t-input value="{{formData.department}}"
|
|
||||||
borderless
|
|
||||||
label="科室"
|
|
||||||
clearable="{{false}}"
|
|
||||||
placeholder="请输入科室名称"
|
|
||||||
bind:change="onInputChange"
|
|
||||||
data-field="department" />
|
|
||||||
|
|
||||||
<view class="btn">
|
|
||||||
<t-button block
|
|
||||||
theme="primary" bind:tap="onSubmit">
|
|
||||||
确认
|
|
||||||
</t-button>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
@@ -1,21 +1,100 @@
|
|||||||
|
import request from "@/utils/request"
|
||||||
|
import { getToken, setToken } from "@/utils/auth/manageToken"
|
||||||
|
import { formatDate } from "@/utils/common"
|
||||||
|
const app = getApp()
|
||||||
Page({
|
Page({
|
||||||
data: {
|
data: {
|
||||||
|
loading: true,
|
||||||
|
parmas: {},
|
||||||
|
mood: "manual",
|
||||||
showPicker: false,
|
showPicker: false,
|
||||||
date: new Date().getTime(),
|
date: new Date().getTime(),
|
||||||
|
|
||||||
//手术
|
//手术
|
||||||
showSurgery: false,
|
showSurgery: false,
|
||||||
surgeryList: [],
|
surgeryList: [],
|
||||||
selectSurgery: [],
|
selectSurgery: [],
|
||||||
|
//医院信息
|
||||||
|
hospital: "",
|
||||||
|
department: "",
|
||||||
|
//其他信息
|
||||||
age: "",
|
age: "",
|
||||||
allergy: "",
|
allergy: "",
|
||||||
comorbidity: "",
|
comorbidity: "",
|
||||||
},
|
},
|
||||||
|
onLoad(e) {
|
||||||
|
if (Object.keys(e).length > 0) {
|
||||||
|
this.setData({
|
||||||
|
parmas: e,
|
||||||
|
mood: "scan"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.init()
|
||||||
|
},
|
||||||
|
//初始化
|
||||||
|
async init() {
|
||||||
|
let token = getToken()
|
||||||
|
//如果存在
|
||||||
|
if (token) {
|
||||||
|
let info = await request.get("/my-info")
|
||||||
|
this.handUser(info)
|
||||||
|
} else {
|
||||||
|
wx.login({
|
||||||
|
success: async (res) => {
|
||||||
|
let response = await request.post("/login", {
|
||||||
|
"wx_code": res.code
|
||||||
|
})
|
||||||
|
setToken(response.accessToken)
|
||||||
|
this.handUser(response)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
//处理信息
|
||||||
|
async handUser(data) {
|
||||||
|
app.globalData.userInfo = data.userInfo
|
||||||
|
if (data.needProfile == 0) {
|
||||||
|
wx.switchTab({
|
||||||
|
url: "/pages/home/index",
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
let res = await request.get("/profile/surgicals")
|
||||||
|
this.setData({
|
||||||
|
surgeryList: res.list,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.setData({
|
||||||
|
loading: false,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
onInputChange(e) {
|
onInputChange(e) {
|
||||||
const { field } = e.currentTarget.dataset;
|
const { field } = e.currentTarget.dataset;
|
||||||
this.setData({
|
this.setData({
|
||||||
[`${field}`]: e.detail.value,
|
[`${field}`]: e.detail.value,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
//选择手术
|
||||||
|
changeSurgeryShow() {
|
||||||
|
this.setData({
|
||||||
|
showSurgery: !this.data.showSurgery
|
||||||
|
})
|
||||||
|
},
|
||||||
|
handSelectSurgery(e) {
|
||||||
|
let { data } = e.currentTarget.dataset
|
||||||
|
let { selectSurgery } = this.data
|
||||||
|
let isHave = selectSurgery.find(item => item.id == data.id)
|
||||||
|
if (isHave) {
|
||||||
|
this.setData({
|
||||||
|
selectSurgery: selectSurgery.filter((item) => item.id != data.id)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
this.setData({
|
||||||
|
selectSurgery: [...selectSurgery, data]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
//选择时间
|
//选择时间
|
||||||
chaneTimeShow() {
|
chaneTimeShow() {
|
||||||
this.setData({
|
this.setData({
|
||||||
@@ -29,22 +108,26 @@ Page({
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
//选择手术
|
|
||||||
changeSurgeryShow() {
|
|
||||||
this.setData({
|
|
||||||
showSurgery: !this.data.showSurgery
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
//提交
|
//提交
|
||||||
onSubmit() {
|
async onSubmit() {
|
||||||
let { date, age, allergy, comorbidity } = this.data
|
let { mood, hospital, department, date, age, allergy, comorbidity, parmas, selectSurgery } = this.data
|
||||||
let errorText = ""
|
let errorText = ""
|
||||||
if (!date) {
|
if (mood == 'manual' && !hospital.trim()) {
|
||||||
|
errorText = "请输入医院"
|
||||||
|
}
|
||||||
|
else if (mood == 'manual' && !department.trim()) {
|
||||||
|
errorText = "请输入科室"
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (selectSurgery.length == 0) {
|
||||||
|
errorText = "请选择手术"
|
||||||
|
}
|
||||||
|
else if (!date) {
|
||||||
errorText = "请选择时间"
|
errorText = "请选择时间"
|
||||||
}
|
}
|
||||||
if (!age.trim()) {
|
else if (!age.trim()) {
|
||||||
errorText = "请填写年龄"
|
errorText = "请填写年龄"
|
||||||
}
|
}
|
||||||
if (errorText) {
|
if (errorText) {
|
||||||
@@ -54,8 +137,29 @@ Page({
|
|||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
|
wx.showLoading({
|
||||||
|
title: '提交中',
|
||||||
|
mask: true
|
||||||
|
})
|
||||||
|
await request.post("/profile", {
|
||||||
|
entry_mode: mood,
|
||||||
|
...parmas,
|
||||||
|
hospital_name: hospital,
|
||||||
|
department_name: department,
|
||||||
|
surgical_ids: selectSurgery.map(item => item.id),
|
||||||
|
surgical_date: formatDate(date, 'YYYY-MM-DD'),
|
||||||
|
age: age,
|
||||||
|
allergy_history: allergy,
|
||||||
|
complication: comorbidity
|
||||||
|
})
|
||||||
|
wx.hideLoading()
|
||||||
wx.switchTab({
|
wx.switchTab({
|
||||||
url: '/pages/home/index',
|
url: '/pages/home/index',
|
||||||
})
|
})
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
wx.hideLoading()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
page {
|
.page {
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@@ -21,6 +21,7 @@ page {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
height: 0;
|
height: 0;
|
||||||
@@ -29,6 +30,10 @@ page {
|
|||||||
border-radius: 30rpx 30rpx 0 0;
|
border-radius: 30rpx 30rpx 0 0;
|
||||||
padding: 50rpx 0 0;
|
padding: 50rpx 0 0;
|
||||||
|
|
||||||
|
.ce {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
.text-1 {
|
.text-1 {
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
font-size: 45rpx;
|
font-size: 45rpx;
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
<wxs src="/utils/wxs/comment.wxs"
|
<wxs src="/utils/wxs/comment.wxs"
|
||||||
module="utils"></wxs>
|
module="utils"></wxs>
|
||||||
|
|
||||||
|
<view class="page"
|
||||||
|
wx:if="{{!loading}}">
|
||||||
<view class="banner">
|
<view class="banner">
|
||||||
<t-navbar t-class="fixed-nav"
|
<t-navbar t-class="fixed-nav"
|
||||||
fixed="{{false}}" />
|
fixed="{{false}}" />
|
||||||
@@ -12,10 +15,27 @@
|
|||||||
<scroll-view class="content"
|
<scroll-view class="content"
|
||||||
scroll-y>
|
scroll-y>
|
||||||
<view class="text-1">建立康复档案</view>
|
<view class="text-1">建立康复档案</view>
|
||||||
|
<t-cell title="医院"
|
||||||
|
wx:if="{{mood == 'manual'}}">
|
||||||
|
<input slot="note"
|
||||||
|
placeholder="请输入医院"
|
||||||
|
data-field="hospital"
|
||||||
|
bind:change="onInputChange" />
|
||||||
|
</t-cell>
|
||||||
|
<t-cell title="科室"
|
||||||
|
wx:if="{{mood == 'manual'}}">
|
||||||
|
<input slot="note"
|
||||||
|
placeholder="请输入科室"
|
||||||
|
data-field="department"
|
||||||
|
bind:change="onInputChange" />
|
||||||
|
</t-cell>
|
||||||
<t-cell title="选择手术"
|
<t-cell title="选择手术"
|
||||||
arrow
|
arrow
|
||||||
note="请选择"
|
t-class-title="ce"
|
||||||
bind:tap="changeSurgeryShow">
|
bind:tap="changeSurgeryShow">
|
||||||
|
<view slot="note">
|
||||||
|
{{select.getNames(selectSurgery)}}
|
||||||
|
</view>
|
||||||
</t-cell>
|
</t-cell>
|
||||||
<t-cell title="手术日期"
|
<t-cell title="手术日期"
|
||||||
arrow
|
arrow
|
||||||
@@ -49,6 +69,15 @@
|
|||||||
bind:tap="onSubmit">下一步
|
bind:tap="onSubmit">下一步
|
||||||
</t-button>
|
</t-button>
|
||||||
</view>
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="flex-center"
|
||||||
|
style="height: 100vh;"
|
||||||
|
wx:else>
|
||||||
|
<t-loading theme="circular"
|
||||||
|
size="40rpx" />
|
||||||
|
</view>
|
||||||
|
|
||||||
|
|
||||||
<t-popup visible="{{showSurgery}}"
|
<t-popup visible="{{showSurgery}}"
|
||||||
placement="bottom"
|
placement="bottom"
|
||||||
@@ -57,9 +86,14 @@
|
|||||||
<view class="title">手术列表</view>
|
<view class="title">手术列表</view>
|
||||||
<scroll-view class="surgery-list"
|
<scroll-view class="surgery-list"
|
||||||
scroll-y>
|
scroll-y>
|
||||||
<view class="flex-between surgery-item " wx:for="{{6}}" wx:key="index">
|
<view class="flex-between surgery-item "
|
||||||
<view class="name">测试手术名字</view>
|
wx:for="{{surgeryList}}"
|
||||||
<t-icon name="check" />
|
wx:key="index"
|
||||||
|
data-data="{{item}}"
|
||||||
|
bind:tap="handSelectSurgery">
|
||||||
|
<view class="name">{{item.name}}</view>
|
||||||
|
<t-icon name="check"
|
||||||
|
wx:if="{{select.isSelected(item.id, selectSurgery)}}" />
|
||||||
</view>
|
</view>
|
||||||
</scroll-view>
|
</scroll-view>
|
||||||
</view>
|
</view>
|
||||||
@@ -73,3 +107,27 @@
|
|||||||
format="YYYY-MM-DD"
|
format="YYYY-MM-DD"
|
||||||
bindconfirm="onTimeConfirm"
|
bindconfirm="onTimeConfirm"
|
||||||
bindclose="chaneTimeShow" />
|
bindclose="chaneTimeShow" />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<wxs module="select">
|
||||||
|
module.exports = {
|
||||||
|
isSelected: function (id, list) {
|
||||||
|
if (!list || !list.length) return false;
|
||||||
|
for (var i = 0; i < list.length; i++) {
|
||||||
|
if (list[i].id === id) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
getNames: function (list) {
|
||||||
|
if (!list || !list.length) return "请选择";
|
||||||
|
// 拼接名字,逗号分隔
|
||||||
|
var names = "";
|
||||||
|
for (var i = 0; i < list.length; i++) {
|
||||||
|
names += list[i].name;
|
||||||
|
if (i < list.length - 1) names += ", ";
|
||||||
|
}
|
||||||
|
return names;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</wxs>
|
||||||
@@ -12,20 +12,19 @@ Page({
|
|||||||
let state = wx.getStorageSync(this.data.key);
|
let state = wx.getStorageSync(this.data.key);
|
||||||
if (state) {
|
if (state) {
|
||||||
wx.redirectTo({
|
wx.redirectTo({
|
||||||
url: "/pages/joinFlow/access/index",
|
url: "/pages/joinFlow/person/index",
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
this.setData({
|
this.setData({
|
||||||
loading: false
|
loading: false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
handNext() {
|
handNext() {
|
||||||
wx.setStorageSync(this.data.key, true)
|
wx.setStorageSync(this.data.key, true)
|
||||||
wx.redirectTo({
|
wx.redirectTo({
|
||||||
url: "/pages/home/index",
|
url: "/pages/joinFlow/person/index"
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"compileType": "miniprogram",
|
"compileType": "miniprogram",
|
||||||
"libVersion": "trial",
|
"libVersion": "3.15.1",
|
||||||
"setting": {
|
"setting": {
|
||||||
"coverView": true,
|
"coverView": true,
|
||||||
"es6": true,
|
"es6": true,
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"projectname": "wx_app_template",
|
"projectname": "wx_app_template",
|
||||||
"setting": {
|
"setting": {
|
||||||
"compileHotReLoad": true,
|
"compileHotReLoad": true,
|
||||||
"urlCheck": true,
|
"urlCheck": false,
|
||||||
"coverView": true,
|
"coverView": true,
|
||||||
"lazyloadPlaceholderEnable": false,
|
"lazyloadPlaceholderEnable": false,
|
||||||
"skylineRenderEnable": false,
|
"skylineRenderEnable": false,
|
||||||
@@ -20,17 +20,5 @@
|
|||||||
"bigPackageSizeSupport": false
|
"bigPackageSizeSupport": false
|
||||||
},
|
},
|
||||||
"libVersion": "3.15.1",
|
"libVersion": "3.15.1",
|
||||||
"condition": {
|
"condition": {}
|
||||||
"miniprogram": {
|
|
||||||
"list": [
|
|
||||||
{
|
|
||||||
"name": "pages/home/index",
|
|
||||||
"pathName": "pages/home/index",
|
|
||||||
"query": "",
|
|
||||||
"scene": null,
|
|
||||||
"launchMode": "default"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -73,3 +73,19 @@ export function uploadQiuFile(path, file, is_public = 1) {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 复制文字内容
|
||||||
|
* @param {文本} text
|
||||||
|
*/
|
||||||
|
export function copyText(text) {
|
||||||
|
wx.setClipboardData({
|
||||||
|
data: text,
|
||||||
|
success() {
|
||||||
|
wx.showToast({
|
||||||
|
title: '已复制到剪切板',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -2,11 +2,11 @@ import httpEnv from "./auth/env"
|
|||||||
import { getToken, removeToken } from "./auth/manageToken"
|
import { getToken, removeToken } from "./auth/manageToken"
|
||||||
const baseApi = {
|
const baseApi = {
|
||||||
//开发版
|
//开发版
|
||||||
develop: "https://curainwxapp.test.tuzuu.com/api",
|
develop: "https://kairos-wx.test.tuzuu.com/api",
|
||||||
// 体验版
|
// 体验版
|
||||||
trial: "https://curainwxapp.test.tuzuu.com/api",
|
trial: "https://kairos-wx.test.tuzuu.com/api",
|
||||||
// 正式版
|
// 正式版
|
||||||
release: "https://yidaojia.cells.org.cn/api"
|
release: "https://kairos-wx.test.tuzuu.com/api",
|
||||||
}
|
}
|
||||||
//获取当前环境的接口前缀
|
//获取当前环境的接口前缀
|
||||||
export const baseUrl = baseApi[httpEnv]
|
export const baseUrl = baseApi[httpEnv]
|
||||||
@@ -82,4 +82,65 @@ request.post = function (url, options) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//流式
|
||||||
|
let lastChunk = '' //流可能会被截断,需要补充
|
||||||
|
export function streamRequest(url, data, onChunkReceived) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const token = getToken()
|
||||||
|
let header = {}
|
||||||
|
if (token) {
|
||||||
|
header.Authorization = 'Bearer ' + token;
|
||||||
|
}
|
||||||
|
let requestTask = wx.request({
|
||||||
|
url: baseUrl + url,
|
||||||
|
data: data || {},
|
||||||
|
method: 'POST',
|
||||||
|
header,
|
||||||
|
timeout: 100000,
|
||||||
|
responseType: "arraybuffer",
|
||||||
|
enableChunked: true, //关键!开启流式传输模式
|
||||||
|
success: () => {
|
||||||
|
resolve()
|
||||||
|
},
|
||||||
|
fail: (e) => {
|
||||||
|
console.log(e);
|
||||||
|
reject()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
//处理流
|
||||||
|
if (onChunkReceived) {
|
||||||
|
lastChunk = ''
|
||||||
|
requestTask.onChunkReceived((response) => {
|
||||||
|
let data = response.data;
|
||||||
|
// console.log(decodeStream(data));
|
||||||
|
onChunkReceived(decodeStream(data))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
//流素具解码
|
||||||
|
function decodeStream(data) {
|
||||||
|
let uint8Array = new Uint8Array(data); // 将 ArrayBuffer 转换为 Uint8Array
|
||||||
|
let responseText = decodeURIComponent(escape(String.fromCharCode.apply(null, uint8Array))); // 使用 apply 扩展字节
|
||||||
|
// 处理数据,移除前缀等操作
|
||||||
|
if (lastChunk) {
|
||||||
|
responseText = "data: " + lastChunk + responseText
|
||||||
|
lastChunk = ""
|
||||||
|
}
|
||||||
|
// 处理数据,移除前缀等操作
|
||||||
|
responseText = responseText.replaceAll("data: ", '');
|
||||||
|
let jsonStrings = responseText.trim().split(/\n+/);
|
||||||
|
// 过滤掉解析失败的部分
|
||||||
|
let jsonArray = jsonStrings.map(jsonStr => {
|
||||||
|
try {
|
||||||
|
return JSON.parse(jsonStr);
|
||||||
|
} catch (e) {
|
||||||
|
lastChunk = jsonStr
|
||||||
|
console.error('JSON格式不正确(已做兼容处理):');
|
||||||
|
return null; // 如果解析失败,返回null
|
||||||
|
}
|
||||||
|
}).filter(item => item !== null);
|
||||||
|
return jsonArray
|
||||||
|
}
|
||||||
|
|
||||||
export default request
|
export default request
|
||||||
@@ -26,4 +26,38 @@ module.exports = {
|
|||||||
.replace(getRegExp('ss'), ss)
|
.replace(getRegExp('ss'), ss)
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* 获取浅色标签颜色
|
||||||
|
* @param {string} hexColor 如 "#e3f9e9"
|
||||||
|
*/
|
||||||
|
getLightColor: function (color, level) {
|
||||||
|
if (!color || color.indexOf('#') === -1) return color;
|
||||||
|
|
||||||
|
// 默认变浅程度
|
||||||
|
var weight = level !== undefined ? level : 0.9;
|
||||||
|
|
||||||
|
// 处理 #fff 这种简写
|
||||||
|
var hex = color.slice(1);
|
||||||
|
if (hex.length === 3) {
|
||||||
|
hex = hex.charAt(0) + hex.charAt(0) + hex.charAt(1) + hex.charAt(1) + hex.charAt(2) + hex.charAt(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提取 RGB
|
||||||
|
var r = parseInt(hex.substring(0, 2), 16);
|
||||||
|
var g = parseInt(hex.substring(2, 4), 16);
|
||||||
|
var b = parseInt(hex.substring(4, 6), 16);
|
||||||
|
|
||||||
|
// 与白色(255)混合逻辑:新颜色 = 原颜色 * (1 - weight) + 255 * weight
|
||||||
|
r = Math.floor(r * (1 - weight) + 255 * weight);
|
||||||
|
g = Math.floor(g * (1 - weight) + 255 * weight);
|
||||||
|
b = Math.floor(b * (1 - weight) + 255 * weight);
|
||||||
|
|
||||||
|
// 转回 16 进制
|
||||||
|
var toString16 = function (n) {
|
||||||
|
var s = n.toString(16);
|
||||||
|
return s.length === 1 ? '0' + s : s;
|
||||||
|
};
|
||||||
|
|
||||||
|
return '#' + toString16(r) + toString16(g) + toString16(b);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
Reference in New Issue
Block a user