Compare commits

..

9 Commits

Binary file not shown.

@ -183,7 +183,7 @@ export const queryPrimaryDetailInfo = (data?: object) => {
/** 使
*/
export const talkByVideo = (data?: object) => {
return http.request("post", "/virtual-patient/ask/talkByVideo", {
return http.request("post", "/virtual-patient/ask/talkByVideoAndTts", {
data
});
};
@ -218,3 +218,21 @@ export const deleteProcess = (data?: object) => {
params: data
});
};
/**
*/
export const queryQaRecordForFeedback = (data?: object) => {
return http.request(
"get",
"/virtual-patient/feedback/queryQaRecordForFeedback",
{
params: data
}
);
};
/**
*/
export const saveFeedback = (data?: object) => {
return http.request("post", "/virtual-patient/feedback/saveFeedback", {
data
});
};

@ -33,3 +33,19 @@ export const getLogin = (data?: object) => {
export const refreshTokenApi = (data?: object) => {
return http.request<RefreshTokenResult>("post", "/refreshToken", { data });
};
/** 用户注册 */
export const getRegister = (data?: object) => {
return http.request<UserResult>("post", "/virtual-patient/user/register", {
data
});
};
/** 修改密码 */
export const changePassWord = (data?: object) => {
return http.request<UserResult>(
"post",
"/virtual-patient/user/changePassWord",
{
data
}
);
};

@ -20,3 +20,13 @@ export const uploadFile = (data?: object) => {
{ headers: { "Content-Type": "multipart/form-data" } }
);
};
export const loadFileBase64 = (data?: object) => {
return http.request(
"get",
"/virtual-patient-manage/fileManage/loadFileBase64",
{
params: data
}
);
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 959 B

@ -0,0 +1,11 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="heli-xuanzhong" clip-path="url(#clip0_542_564)">
<path id="Vector" d="M10 18.3337C12.3012 18.3337 14.3845 17.4009 15.8925 15.8929C17.4006 14.3848 18.3333 12.3015 18.3333 10.0003C18.3333 7.69916 17.4006 5.61583 15.8925 4.10777C14.3845 2.59973 12.3012 1.66699 10 1.66699C7.69884 1.66699 5.6155 2.59973 4.10745 4.10777C2.59941 5.61583 1.66667 7.69916 1.66667 10.0003C1.66667 12.3015 2.59941 14.3848 4.10745 15.8929C5.6155 17.4009 7.69884 18.3337 10 18.3337Z" stroke="#00975E" stroke-width="1.5" stroke-linejoin="round"/>
<path id="Vector_2" d="M6.66667 10L9.16667 12.5L14.1667 7.5" stroke="#00975E" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</g>
<defs>
<clipPath id="clip0_542_564">
<rect width="20" height="20" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 880 B

@ -0,0 +1,12 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="buheli-xuanzhong" clip-path="url(#clip0_542_568)">
<path id="Vector" d="M10 18.3337C14.6024 18.3337 18.3333 14.6027 18.3333 10.0003C18.3333 5.39795 14.6024 1.66699 10 1.66699C5.39762 1.66699 1.66666 5.39795 1.66666 10.0003C1.66666 14.6027 5.39762 18.3337 10 18.3337Z" stroke="#FF3429" stroke-width="1.5" stroke-linejoin="round"/>
<path id="Vector_2" d="M12.357 7.64258L7.64291 12.3566" stroke="#FF3429" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path id="Vector_3" d="M7.64304 7.64258L12.3571 12.3566" stroke="#FF3429" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</g>
<defs>
<clipPath id="clip0_542_568">
<rect width="20" height="20" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 829 B

@ -0,0 +1,11 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="heli" clip-path="url(#clip0_542_573)">
<path id="Vector" d="M10 18.3337C12.3012 18.3337 14.3845 17.4009 15.8925 15.8929C17.4006 14.3848 18.3333 12.3015 18.3333 10.0003C18.3333 7.69916 17.4006 5.61583 15.8925 4.10777C14.3845 2.59973 12.3012 1.66699 10 1.66699C7.69884 1.66699 5.6155 2.59973 4.10745 4.10777C2.59941 5.61583 1.66667 7.69916 1.66667 10.0003C1.66667 12.3015 2.59941 14.3848 4.10745 15.8929C5.6155 17.4009 7.69884 18.3337 10 18.3337Z" stroke="#999999" stroke-width="1.5" stroke-linejoin="round"/>
<path id="Vector_2" d="M6.66667 10L9.16667 12.5L14.1667 7.5" stroke="#999999" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</g>
<defs>
<clipPath id="clip0_542_573">
<rect width="20" height="20" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 870 B

@ -0,0 +1,12 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="buheli" clip-path="url(#clip0_542_577)">
<path id="Vector" d="M10 18.3337C14.6024 18.3337 18.3333 14.6027 18.3333 10.0003C18.3333 5.39795 14.6024 1.66699 10 1.66699C5.39762 1.66699 1.66666 5.39795 1.66666 10.0003C1.66666 14.6027 5.39762 18.3337 10 18.3337Z" stroke="#999999" stroke-width="1.5" stroke-linejoin="round"/>
<path id="Vector_2" d="M12.357 7.64258L7.64291 12.3566" stroke="#999999" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path id="Vector_3" d="M7.64304 7.64258L12.3571 12.3566" stroke="#999999" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</g>
<defs>
<clipPath id="clip0_542_577">
<rect width="20" height="20" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 819 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

@ -37,9 +37,13 @@ export const useConsultationStore = defineStore({
exhalationFlag: false, //呼出服务
voiceFlag: true,
planTypeFlag: "", // 处置计划类型
supportActionId: [] // 呼出辅助检查
supportActionId: [], // 呼出辅助检查
voiceStartFlag: false //是否开始语音问诊
}),
actions: {
changeVoiceFlag(data) {
this.voiceStartFlag = data;
},
changeActivedKey(data) {
this.activedKey = data;
if (data !== 1) {

@ -12,9 +12,9 @@ import {
import { stringify } from "qs";
import NProgress from "../progress";
import { getToken, formatToken } from "@/utils/auth";
// import { useUserStoreHook } from "@/store/modules/user";
import { useUserStoreHook } from "@/store/modules/user";
import { message } from "../message";
import router from "@/router";
// import router from "@/router";
// 相关配置请参考www.axios-js.com/zh-cn/docs/#axios-request-config-1
const defaultConfig: AxiosRequestConfig = {
@ -125,7 +125,7 @@ class PureHttp {
instance.interceptors.response.use(
(response: PureHttpResponse) => {
if (response.data.code === 401) {
router.push("/login");
useUserStoreHook().logOut();
return;
}
if (response.data.code !== 200) {

@ -1,3 +1,235 @@
<!-- <script setup lang="ts">
import { nextTick, reactive, ref } from "vue";
import { FormInstance } from "element-plus";
import { message } from "@/utils/message";
// import { useRoute } from "vue-router";
defineOptions({
name: "AddEdit"
});
const isEditFlag = ref(false);
const diseaseList = ref([]);
const id = ref("");
const dialogVisible = ref(false);
const formData = reactive({
patientGender: "",
directoryDesc: "",
patientSelfDesc: "",
patientAge: "",
diseaseId: ""
});
const ruleFormRef = ref<FormInstance>();
const rules = {
patientGender: [{ required: true, message: "请选择", trigger: "change" }],
directoryDesc: [{ required: true, message: "请输入", trigger: "change" }]
};
defineExpose({
async open(item) {
dialogVisible.value = true;
await nextTick();
if (item) {
for (const key in item) {
// eslint-disable-next-line no-prototype-builtins
if (formData.hasOwnProperty(key)) {
formData[key] = item[key];
}
}
isEditFlag.value = true;
id.value = item.id;
}
}
});
const resetForm = () => {
ruleFormRef.value.resetFields();
};
const closeDialog = () => {
dialogVisible.value = false;
isEditFlag.value = false;
resetForm();
};
const emit = defineEmits(["update"]);
const reset = () => {
ruleFormRef.value.resetFields();
};
const save = (formEl: FormInstance | undefined) => {
formEl.validate(async (valid, fields) => {
if (valid) {
// formData.result = refWangEditor.value.valueHtml;
// const params = {
// ...formData,
// result: refWangEditor.value.valueHtml,
// diseaseId: route.query.id
// };
if (isEditFlag.value) {
// const res: any = await updateSupportInspect({
// ...params,
// id: id.value
// });
if (res.code === 200) {
message("修改成功", { type: "success" });
id.value = "";
}
} else {
// const res: any = await addSupportInspect(params);
// if (res.code === 200) {
// message("", { type: "success" });
// }
}
dialogVisible.value = false;
emit("update");
} else {
return fields;
}
});
};
</script>
<template>
<div>
<el-drawer
:size="650"
append-to-body
v-model="dialogVisible"
:show-close="false"
:with-header="false"
:before-close="closeDialog"
custom-class="AddEdit"
>
<div class="AddEdit">
<div class="header-title">
<div class="tip" />
<span>新建病历</span>
</div>
<div class="line" />
<el-form
ref="ruleFormRef"
:model="formData"
:rules="rules"
label-width="80px"
>
<el-form-item label="姓名" prop="directoryDesc">
<el-input
size="large"
placeholder="请输入"
v-model="formData.directoryDesc"
/>
</el-form-item>
<el-form-item label="性别" prop="patientGender">
<el-radio-group size="large" v-model="formData.patientGender">
<el-radio label="男" />
<el-radio label="女" />
</el-radio-group>
</el-form-item>
<el-form-item label="主诉" prop="patientSelfDesc">
<el-input size="large" v-model="formData.patientSelfDesc" />
</el-form-item>
<el-form-item label="年龄" prop="patientAge">
<el-input
size="large"
maxLength="3"
v-model="formData.patientAge"
/>
</el-form-item>
<el-form-item label="初步诊断:" prop="diseaseId">
<el-select
size="large"
filterable
clearable
v-model="formData.diseaseId"
class="form_select"
style="width: 100%"
placeholder="请选择初步诊断"
>
<el-option
v-for="item in diseaseList"
:key="item.id"
:label="item.diseaseName"
:value="item.id"
/>
</el-select>
</el-form-item>
</el-form>
</div>
<template #footer>
<div class="footer_btn">
<div class="reset" @click="reset()"></div>
<div class="main" @click="save(ruleFormRef)"></div>
</div>
</template>
</el-drawer>
</div>
</template>
<style lang="scss" scoped>
.AddEdit {
:deep(.el-form-item__label) {
font-weight: 400;
color: #333;
}
.header-title {
display: flex;
align-items: center;
// border-left: 6px solid #4287ff;
font-size: 20px;
font-weight: bold;
color: #2b3f54;
.tip {
width: 6px;
height: 20px;
margin-right: 10px;
line-height: 20px;
background: #4287ff;
}
}
.line {
position: relative;
left: -20px;
width: 605px;
height: 1px;
margin: 24px 0;
background: rgb(91 139 255 / 30%);
}
.footer_btn {
display: flex;
align-items: center;
justify-content: flex-end;
margin-top: 16px;
.reset {
width: 188px;
height: 48px;
margin-right: 24px;
font-size: 16px;
font-weight: 400;
line-height: 48px;
color: #4287ff;
text-align: center;
cursor: pointer;
background: #fff;
border: 1px solid #4287ff;
border-radius: 6px;
}
.main {
width: 188px;
height: 48px;
font-size: 16px;
line-height: 48px;
color: #fff;
text-align: center;
cursor: pointer;
background: #4287ff;
border: 1px solid #4287ff;
border-radius: 6px;
}
}
}
</style> -->
<script setup lang="ts">
import { onMounted } from "vue";
import MainView from "./page/index.vue";

@ -35,7 +35,7 @@ const columns: TableColumnList = [
},
{
label: "回复",
prop: "defaultAnswer"
prop: "medicalRecAnswer"
}
];
const planColumns: TableColumnList = [
@ -117,7 +117,7 @@ onMounted(() => {
</div>
</div>
<pure-table
style="width: 100%; max-height: 500px"
style="width: 100%; height: 500px"
align-whole="center"
showOverflowTooltip
adaptive
@ -137,7 +137,7 @@ onMounted(() => {
</div>
</div>
<pure-table
style="width: 100%; max-height: 500px"
style="width: 100%; height: 500px"
align-whole="center"
showOverflowTooltip
adaptive

@ -0,0 +1,215 @@
<script setup lang="ts">
import { nextTick, reactive, ref } from "vue";
import { FormInstance } from "element-plus";
import { message } from "@/utils/message";
// import { useRoute } from "vue-router";
defineOptions({
name: "AddCase"
});
const isEditFlag = ref(false);
const diseaseList = ref([]);
const id = ref("");
const dialogVisible = ref(false);
const formData = reactive({
patientGender: "",
directoryDesc: "",
patientSelfDesc: "",
patientAge: "",
diseaseId: ""
});
const ruleFormRef = ref<FormInstance>();
const rules = {
patientGender: [{ required: true, message: "请选择", trigger: "change" }],
directoryDesc: [{ required: true, message: "请输入", trigger: "change" }]
};
defineExpose({
async open(item) {
dialogVisible.value = true;
await nextTick();
if (item) {
for (const key in item) {
// eslint-disable-next-line no-prototype-builtins
if (formData.hasOwnProperty(key)) {
formData[key] = item[key];
}
}
isEditFlag.value = true;
id.value = item.id;
}
}
});
const resetForm = () => {
ruleFormRef.value.resetFields();
};
const closeDialog = () => {
dialogVisible.value = false;
isEditFlag.value = false;
resetForm();
};
const emit = defineEmits(["update"]);
const reset = () => {
ruleFormRef.value.resetFields();
};
const save = (formEl: FormInstance | undefined) => {
formEl.validate(async (valid, fields) => {
if (valid) {
// formData.result = refWangEditor.value.valueHtml;
// const params = {
// ...formData,
// result: refWangEditor.value.valueHtml,
// diseaseId: route.query.id
// };
if (isEditFlag.value) {
// const res: any = await updateSupportInspect({
// ...params,
// id: id.value
// });
if (res.code === 200) {
message("修改成功", { type: "success" });
id.value = "";
}
} else {
// const res: any = await addSupportInspect(params);
// if (res.code === 200) {
// message("", { type: "success" });
// }
}
dialogVisible.value = false;
emit("update");
} else {
return fields;
}
});
};
</script>
<template>
<div>
<el-drawer
:size="650"
append-to-body
v-model="dialogVisible"
:show-close="false"
:with-header="false"
:before-close="closeDialog"
custom-class="AddEdit"
>
<div class="AddEdit">
<div class="header-title">
<div class="tip" />
<span>添加电子病历项</span>
</div>
<div class="line" />
<el-form
ref="ruleFormRef"
:model="formData"
:rules="rules"
label-width="80px"
>
<el-form-item label="选择类目" prop="directoryDesc">
<el-select
size="large"
filterable
clearable
v-model="formData.diseaseId"
class="form_select"
style="width: 100%"
placeholder="请选择选择类目"
>
<el-option
v-for="item in diseaseList"
:key="item.id"
:label="item.diseaseName"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="名称" prop="patientGender">
<el-input size="large" v-model="formData.patientSelfDesc" />
</el-form-item>
<el-form-item label="内容" prop="patientSelfDesc">
<el-input size="large" v-model="formData.patientSelfDesc" />
</el-form-item>
</el-form>
</div>
<template #footer>
<div class="footer_btn">
<div class="reset" @click="reset()"></div>
<div class="main" @click="save(ruleFormRef)"></div>
</div>
</template>
</el-drawer>
</div>
</template>
<style lang="scss" scoped>
.AddEdit {
:deep(.el-form-item__label) {
font-weight: 400;
color: #333;
}
.header-title {
display: flex;
align-items: center;
// border-left: 6px solid #4287ff;
font-size: 20px;
font-weight: bold;
color: #2b3f54;
.tip {
width: 6px;
height: 20px;
margin-right: 10px;
line-height: 20px;
background: #4287ff;
}
}
.line {
position: relative;
left: -20px;
width: 605px;
height: 1px;
margin: 24px 0;
background: rgb(91 139 255 / 30%);
}
.footer_btn {
display: flex;
align-items: center;
justify-content: flex-end;
margin-top: 16px;
.reset {
width: 188px;
height: 48px;
margin-right: 24px;
font-size: 16px;
font-weight: 400;
line-height: 48px;
color: #4287ff;
text-align: center;
cursor: pointer;
background: #fff;
border: 1px solid #4287ff;
border-radius: 6px;
}
.main {
width: 188px;
height: 48px;
font-size: 16px;
line-height: 48px;
color: #fff;
text-align: center;
cursor: pointer;
background: #4287ff;
border: 1px solid #4287ff;
border-radius: 6px;
}
}
}
</style>

@ -0,0 +1,129 @@
<script setup lang="ts">
import { reactive, ref } from "vue";
import AddCase from "./AddCase.vue";
const AddCaseRef = ref();
const formData = reactive({
patientGender: "",
directoryDesc: "",
patientSelfDesc: "",
patientAge: "",
diseaseId: ""
});
const caseTypeList = ref([]);
const rules = {
patientGender: [{ required: true, message: "请选择", trigger: "change" }],
directoryDesc: [{ required: true, message: "请输入", trigger: "change" }]
};
const add = () => {
AddCaseRef.value.open();
};
</script>
<template>
<div class="ElectronicCase">
<div class="header">
<div class="header_left">
<span>电子病历</span>
</div>
<div class="header_right">
<el-button size="large" class="btn" @click="add" type="primary"
>添加病例项</el-button
>
</div>
</div>
<el-form
ref="ruleFormRef"
:model="formData"
:rules="rules"
label-width="80px"
>
<el-row>
<el-col :span="8">
<el-form-item label="类型" prop="patientGender">
<span>在线默认</span>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="虚拟人" prop="patientGender">
<el-button type="primary" link> 请选择数字人 </el-button>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="病历类型" prop="patientGender">
<el-select
size="large"
filterable
clearable
v-model="formData.diseaseId"
class="form_select"
style="width: 100%"
placeholder="请选择选择类目"
>
<el-option
v-for="item in caseTypeList"
:key="item.id"
:label="item.diseaseName"
:value="item.id"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="姓名" prop="directoryDesc">
<el-input
size="large"
placeholder="请输入"
v-model="formData.directoryDesc"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="性别" prop="directoryDesc">
<el-input
size="large"
placeholder="请输入"
v-model="formData.directoryDesc"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="年龄" prop="directoryDesc">
<el-input
size="large"
placeholder="请输入"
v-model="formData.directoryDesc"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
<AddCase ref="AddCaseRef" />
</div>
</template>
<style lang="scss" scoped>
.ElectronicCase {
flex: 1;
.header {
display: flex;
align-items: center;
justify-content: space-between;
height: 88px;
padding: 0 40px;
margin-bottom: 24px;
border-bottom: 1px solid #d9d9d9;
.header_left {
font-size: 20px;
color: #333;
span {
padding-left: 8px;
border-left: 6px solid #4287ff;
}
}
}
}
</style>

@ -0,0 +1,87 @@
<script setup lang="ts">
import ElectronicCase from "./compontents/ElectronicCase/index.vue";
import { ref } from "vue";
const activedIndex = ref(0);
const navList = ref([
{
name: "电子病历"
},
{
name: "临床问诊"
},
{
name: "临床诊断"
},
{
name: "诊断依据"
},
{
name: "处置计划"
}
]);
</script>
<template>
<div class="editCase main-table">
<div class="editCase_nav">
<div
class="editCase_nav_item"
:class="[activedIndex === index ? 'actived' : '']"
v-for="(item, index) in navList"
:key="index"
>
<div class="line" />
<span>{{ item.name }}</span>
</div>
</div>
<ElectronicCase v-if="activedIndex === 0" />
</div>
</template>
<style lang="scss" scoped>
.editCase {
display: flex;
flex-direction: row !important;
width: 100%;
padding: 0;
.editCase_nav {
display: flex;
flex-direction: column;
align-items: center;
width: 168px;
// justify-content: center;
height: 100%;
padding-top: 24px;
border-right: 1px solid #d9d9d9;
.editCase_nav_item {
display: flex;
align-items: center;
justify-content: center;
width: 120px;
height: 53px;
font-size: 16px;
color: #999;
cursor: pointer;
border-radius: 8px;
.line {
width: 4px;
height: 17px;
margin-right: 12px;
background: #999;
border-radius: 2px;
}
}
.actived {
color: #4287ff;
background: linear-gradient(90deg, rgb(66 135 255 / 10%) 0%, #fff 100%);
.line {
background: #4287ff;
}
}
}
}
</style>

@ -125,7 +125,7 @@ const save = async data => {
if (res.code === 200) {
sessionStorage.setItem("inspectSatus", "1");
useConsultationStoreHooks().changeInspectSatus("1");
message("提交成功", { type: "success" });
message("请配置处置计划", { type: "success" });
emit("save");
}
};

@ -11,6 +11,7 @@ defineOptions({
name: "ConfirmInspect"
});
const route = useRoute();
const processId = ref();
const IdentificationBasisRef = ref();
const PreliminaryDiagnosisRef = ref();
const completed = () => {
@ -35,6 +36,7 @@ const saveOk = () => {
emit("saveOk");
};
onMounted(() => {
processId.value = route.query.processId;
useConsultationStoreHooks().getAskPrimaryList(route.query.processId);
});
//
@ -44,9 +46,10 @@ onBeforeUnmount(async () => {
if (list.length === 0) return;
const params = {
primaryConfirmList: list,
processId: route.query.processId,
processId: route.query.processId ? route.query.processId : processId.value,
tempSaveFlag: 1
};
await confirmPrimaryByAskEnd(params);
});
</script>

@ -101,6 +101,7 @@ const selectItem = item => {
formData.drugRoute = "";
formData.intervalDay = "";
formData.intervalHour = "";
formData.treatmentPlanId = "";
};
const clearData = () => {
formData.firstMeasures = "";
@ -228,6 +229,11 @@ const cancal = () => {
emit("save");
};
onMounted(() => {
if (useConsultationStoreHooks().planTypeFlag !== "") {
formData.disposalMethod = useConsultationStoreHooks().planTypeFlag;
getTree(formData.disposalMethod);
}
queryDrugList();
if (formData.disposalMethod) {
getTree(formData.disposalMethod);

@ -356,7 +356,7 @@ onMounted(() => {
.desc {
margin-top: 16px;
font-size: 12px;
font-size: 16px;
font-weight: 400;
color: #2b3f54;
}

@ -0,0 +1,385 @@
<script setup lang="ts">
import titleIcon from "@/assets/newInquiry/title_icon.png";
import textIcon from "@/assets/newInquiry/text_icon.png";
import actReasonableIcon from "@/assets/svg/consultation/record/act_reasonable.svg";
import actUnreasonableIcon from "@/assets/svg/consultation/record/act_unreasonable.svg";
import reasonableIcon from "@/assets/svg/consultation/record/reasonable.svg";
import unreasonableIcon from "@/assets/svg/consultation/record/unreasonable.svg";
import { queryQaRecordForFeedback, saveFeedback } from "@/api/consultation";
import { reactive, ref } from "vue";
import { onMounted } from "vue";
import { useRoute } from "vue-router";
import { FormInstance } from "element-plus";
import { message } from "@/utils/message";
import { useConsultationStoreHooks } from "@/store/modules/consultation";
const formData = reactive({
evaluateLevel: undefined,
evaluateRemark: ""
});
const route = useRoute();
const ruleFormRef = ref<FormInstance>();
// const feedbackList = ref([
// {
// key: "1",
// name: ""
// },
// {
// key: "2",
// name: ""
// },
// {
// key: "3",
// name: ""
// }
// ]);
const dataList = ref([
// {
// feedbackType: 1,
// remark: "",
// feedback: [],
// question: "",
// anser:
// ""
// }
]);
const rules = {
evaluateLevel: [{ required: true, message: "请选择", trigger: "change" }]
};
const changeStatus = (index, val) => {
const list = [...dataList.value];
list[index].feedbackType = val;
dataList.value = list;
};
const getData = async () => {
const res: any = await queryQaRecordForFeedback({
processId: route.query.processId
});
dataList.value = res.data.qaList;
if (res.data.evaluateLevel !== null && res.data.evaluateLevel !== undefined) {
formData.evaluateLevel = res.data.evaluateLevel;
} else {
formData.evaluateLevel = "";
}
formData.evaluateRemark = res.data.evaluateRemark;
};
const reset = () => {
getData();
};
const save = (formEl: FormInstance | undefined) => {
formEl.validate(async (valid, fields) => {
if (valid) {
const params = {
qaList: dataList.value,
evaluateLevel: formData.evaluateLevel,
evaluateRemark: formData.evaluateRemark,
processId: route.query.processId
};
const res: any = await saveFeedback(params);
if (res.code === 200) {
message("提交成功", { type: "success" });
useConsultationStoreHooks().changeActivedKey(4);
getData();
}
} else {
return fields;
}
});
};
const submit = () => {
console.log("1", dataList.value);
};
onMounted(() => {
getData();
});
</script>
<template>
<div class="ConsultationRecords">
<div class="main">
<div class="evaluate">
<div class="header_title">
<div class="title">
<img :src="titleIcon" alt="" />
<span>问诊评价</span>
</div>
</div>
<el-form
ref="ruleFormRef"
:model="formData"
class="mt-4"
:rules="rules"
label-width="90px"
>
<el-form-item label="预期结果:" prop="evaluateLevel">
<el-radio-group v-model="formData.evaluateLevel">
<el-radio :label="0" size="large">可靠</el-radio>
<el-radio :label="1" size="large">基本可靠</el-radio>
<el-radio :label="2" size="large">仅供参考</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="备注:" prop="evaluateRemark">
<el-input
:rows="4"
type="textarea"
:maxLength="500"
placeholder="请输入"
v-model="formData.evaluateRemark"
/>
</el-form-item>
</el-form>
</div>
<div class="main_content">
<div class="header_title">
<div class="title">
<img :src="textIcon" alt="" />
<span>临床问诊</span>
</div>
</div>
<div class="main_list">
<div class="main_item" v-for="(item, index) in dataList" :key="index">
<div class="main_item_left">
<p class="mb-1">{{ `问诊:${item.question}` }}</p>
<p>{{ `病人:${item.answer}` }}</p>
</div>
<div class="main_item_right">
<div
@click="changeStatus(index, 1)"
class="main_item_right_item"
style="margin-right: 40px"
:class="[item.feedbackType === 1 ? 'act_reasonableIcon' : '']"
>
<actReasonableIcon v-if="item.feedbackType === 1" />
<reasonableIcon v-else />
<span>合理</span>
</div>
<el-dropdown>
<div
@click="changeStatus(index, 2)"
class="main_item_right_item"
:class="[
item.feedbackType === 2 ? 'act_unreasonableIcon' : ''
]"
>
<actUnreasonableIcon v-if="item.feedbackType === 2" />
<unreasonableIcon v-else />
<span>不合理</span>
</div>
<template #dropdown>
<div class="drop_content">
<div class="title">临床问诊反馈</div>
<div class="dropdown_list">
<el-checkbox
size="large"
class="dropdown_list_item"
v-model="item.feedbackTooLong"
:true-label="1"
:false-label="0"
>回答过于冗长</el-checkbox
>
<el-checkbox
size="large"
class="dropdown_list_item"
:true-label="1"
:false-label="0"
v-model="item.feedbackError"
>答非所问</el-checkbox
>
<el-checkbox
size="large"
class="dropdown_list_item"
:true-label="1"
:false-label="0"
v-model="item.feedbackTooShort"
>内容不合理</el-checkbox
>
</div>
<el-input
v-model="item.feedbackRemark"
maxlength="100"
placeholder="请输入"
show-word-limit
type="textarea"
/>
<div class="drop_content_btn" @click="submit"></div>
</div>
</template>
</el-dropdown>
</div>
</div>
</div>
</div>
</div>
<div class="footer_btn">
<div class="reset" @click="reset"></div>
<div class="main_btn" @click="save(ruleFormRef)"></div>
</div>
</div>
</template>
<style lang="scss" scoped>
.ConsultationRecords {
// display: flex;
padding: 32px;
.main {
display: flex;
flex-direction: row-reverse;
width: 100%;
margin: 16px;
.evaluate {
width: 441px;
height: calc(100vh - 250px);
padding: 24px;
margin-right: 24px;
background: #fff;
border-radius: 6px;
box-shadow: 0 0 8px 0 rgb(0 0 0 / 15%);
}
.main_content {
flex: 1;
height: calc(100vh - 250px);
padding: 24px;
margin-right: 16px;
overflow-y: auto;
background: #fff;
border-radius: 6px;
box-shadow: 0 0 8px 0 rgb(0 0 0 / 15%);
.main_list {
.main_item {
display: flex;
align-items: center;
justify-content: space-between;
padding-bottom: 16px;
border-bottom: 1px solid #5b8bff;
.main_item_left {
flex: 1;
padding-top: 24px;
font-size: 16px;
color: #2b3f54;
}
.main_item_right {
display: flex;
width: 200px;
.main_item_right_item {
display: flex;
align-items: center;
cursor: pointer;
span {
margin-left: 8px;
font-size: 14px;
font-weight: 400;
color: #999;
}
}
.act_reasonableIcon span {
color: #00975e;
}
.act_unreasonableIcon span {
color: #ff3429;
}
}
}
}
}
}
.footer_btn {
display: flex;
align-items: center;
justify-content: flex-end;
margin-top: 16px;
margin-right: 32px;
.reset {
width: 188px;
height: 48px;
margin-right: 24px;
font-size: 16px;
font-weight: 400;
line-height: 48px;
color: #4287ff;
text-align: center;
cursor: pointer;
background: #fff;
border: 1px solid #4287ff;
border-radius: 6px;
}
.main_btn {
width: 188px;
height: 48px;
font-size: 16px;
line-height: 48px;
color: #fff;
text-align: center;
cursor: pointer;
background: #4287ff;
border: 1px solid #4287ff;
border-radius: 6px;
}
}
}
</style>
<style lang="scss">
.drop_content {
width: 240px;
height: 295px;
padding: 16px;
background: #fff;
border-radius: 8px;
box-shadow: 0 1px 8px 0 rgb(0 0 0 / 15%);
.title {
font-size: 16px;
font-weight: bold;
color: #2b3f54;
}
.dropdown_list {
display: flex;
flex-direction: column;
.dropdown_list_item {
padding: 0;
// margin-bottom: 8px;
}
.el-checkbox.el-checkbox--large .el-checkbox__inner {
width: 18px;
height: 18px;
}
.el-checkbox__inner::after {
left: 5px;
width: 5px;
height: 9px;
border-width: 2px;
}
}
.drop_content_btn {
width: 80px;
height: 32px;
margin-top: 16px;
margin-left: 60px;
font-size: 14px;
line-height: 32px;
color: #fff;
text-align: center;
cursor: pointer;
background: #4287ff;
border-radius: 6px;
}
}
</style>

@ -56,7 +56,7 @@ onMounted(() => {
:class="[item.answerType === 'patient' ? 'check' : '']"
class="title"
>
<span class="type">{{ item.commonDic?.nameZh || "一般症状" }}</span>
<span class="type">{{ item.commonDic?.nameZh || "系统状态" }}</span>
<span class="name">{{ item.question }}</span>
<CheckIcon v-show="item.answerType === 'patient'" class="icon" />
</div>

@ -54,3 +54,11 @@ const selectPostion = val => {
/>
</div>
</template>
<style lang="scss" scoped>
.positionDetails {
position: relative;
width: 720px;
height: 790px;
margin-left: 20px;
}
</style>

@ -190,6 +190,14 @@ const selectPostion = val => {
});
}
};
//
// const closedCard = () => {
// useConsultationStoreHooks().changeBodyResultInfo({
// name: "",
// value: "",
// postion: ""
// });
// };
</script>
<template>
@ -290,16 +298,17 @@ const selectPostion = val => {
v-show="selectToolInfo.toolName || bodyResultInfo.value"
class="result_card"
>
<div v-show="bodyResultInfo.name" class="result_card_left">
<span>{{ bodyResultInfo.name }}</span>
<span style="margin-top: 16px" v-show="bodyResultInfo.postion">{{
bodyResultInfo.postion
}}</span>
</div>
<div v-show="bodyResultInfo.name" class="result_card_right">
<span :title="bodyResultInfo.value">{{ bodyResultInfo.value }}</span>
</div>
<!-- <div v-show="bodyResultInfo.name" class="result_card_item">
<div class="result_card_content">
<div v-show="bodyResultInfo.name" class="result_card_left">
<span>{{ bodyResultInfo.name }}</span>
<span style="margin-top: 16px" v-show="bodyResultInfo.postion">{{
bodyResultInfo.postion
}}</span>
</div>
<div v-show="bodyResultInfo.name" class="result_card_right">
<span :title="bodyResultInfo.value">{{ bodyResultInfo.value }}</span>
</div>
<!-- <div v-show="bodyResultInfo.name" class="result_card_item">
{{ `体格检查项:${bodyResultInfo.name}` }}
</div>
<div v-show="bodyResultInfo.value" class="result_card_item">
@ -308,8 +317,10 @@ const selectPostion = val => {
<div v-show="bodyResultInfo.postion" class="result_card_item">
{{ `测量位置:${bodyResultInfo.postion}` }}
</div> -->
<div v-show="!bodyResultInfo.name" class="result_card_item">
请点击需要检查的身体部位
<div v-show="!bodyResultInfo.name" class="result_card_item">
请点击需要检查的身体部位
</div>
<!-- <el-icon class="closed"><Close @click="closedCard" /></el-icon> -->
</div>
</div>
@ -350,7 +361,7 @@ const selectPostion = val => {
flex: 1;
// align-items: center;
justify-content: center;
height: calc(100vh - 290px);
height: calc(100vh - 250px);
margin-left: 24px;
overflow-y: auto;
@ -549,11 +560,12 @@ const selectPostion = val => {
.result_card {
position: fixed;
bottom: 40px;
bottom: 65px;
left: 600px;
z-index: 1;
display: flex;
width: calc(100vw - 1220px);
width: calc(100% - 1220px);
min-width: 730px;
min-height: 105px;
padding: 24px;
font-size: 16px;
@ -565,6 +577,19 @@ const selectPostion = val => {
border-radius: 6px;
box-shadow: 0 0 8px 0 rgb(0 0 0 / 15%);
.result_card_content {
position: relative;
display: flex;
width: 100%;
.closed {
position: absolute;
top: -10px;
right: -10px;
cursor: pointer;
}
}
.result_card_left {
display: flex;
flex-direction: column;

@ -21,6 +21,7 @@ defineOptions({
flex-direction: row-reverse;
.voice_consultation {
position: relative;
width: 500px;
margin-left: 16px;
}

@ -17,6 +17,7 @@ defineOptions({
});
const route = useRoute();
const cardType = ref(0);
const isStartFlag = ref(false);
watch(
() => useConsultationStoreHooks().voiceFlag,
val => {
@ -25,16 +26,27 @@ watch(
}
}
);
watch(
() => useConsultationStoreHooks().voiceStartFlag,
val => {
isStartFlag.value = val;
}
);
const dialogVisible = ref(false);
const bodyDialogRef = ref(null);
const suppertDialogRef = ref(null);
const question = ref("");
const changeType = (val: number) => {
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
if (isStartFlag.value) return;
if (val === 2) {
cardType.value = val;
} else {
message("麦克风不可用", { type: "error" });
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
cardType.value = val;
} else {
message("麦克风不可用", { type: "error" });
}
}
};
const sendOption = async () => {
@ -66,6 +78,7 @@ const submit = async (val: string) => {
processId: route.query.processId,
text: val
};
useConsultationStoreHooks().changeVoiceFlag(true);
const { data } = await talkByVideo(params);
if (data.type === 2) {
openBodyDialog(data);
@ -73,7 +86,7 @@ const submit = async (val: string) => {
if (data.type === 3) {
openSuppertDialog(data);
}
emit("getVideo", data.videoBase64);
emit("getVideo", data.voiceBase64);
};
//
const openBodyDialog = (item: any) => {
@ -139,8 +152,8 @@ onMounted(() => {
</template>
<style lang="scss" scoped>
.text_footer {
position: fixed;
bottom: 66px;
position: absolute;
bottom: 24px;
display: flex;
width: 500px;
height: 66px;
@ -165,8 +178,9 @@ onMounted(() => {
}
.main_footer {
position: fixed;
bottom: 66px;
position: absolute;
right: 0;
bottom: 24px;
display: flex;
width: 500px;
height: 66px;

@ -2,38 +2,76 @@
import { ref } from "vue";
import { downLoadUrl } from "@/utils/auth";
import { onMounted } from "vue";
import { loadFileBase64 } from "@/api/utils";
import { useConsultationStoreHooks } from "@/store/modules/consultation";
defineOptions({
name: "PeopleVideo"
});
const videoFlag = ref(false);
const videoUrl = ref("");
const patientSilentVideo = ref("");
const status = ref(false);
const videoPlayer = ref();
const changeVideo = url => {
const audioUrl = ref("");
const patientDummyVideo = ref("");
const changeVideo = async url => {
// if (status.value === false) {
// const myAuto = document.getElementById("myAudio");
// audioUrl.value = `data:audio/mp3;base64, ${url}`;
// await myAuto.load();
// myAuto.play();
// const video = document.createElement("video");
// video.src = downLoadUrl(sessionStorage.getItem("patientDummyVideo"));
// video.controls = false;
// video.autoplay = true;
// video.style.width = "100%";
// video.style.height = "100%";
// video.style.objectFit = "cover";
// video.addEventListener("canplaythrough", () => {
// //
// document.getElementById("video_content").appendChild(video);
// status.value = true;
// videoFlag.value = true;
// });
// video.addEventListener("ended", () => {
// //
// videoFlag.value = false;
// status.value = false;
// video.remove();
// });
// } else {
// setTimeout(() => {
// changeVideo(url);
// }, 1000);
// }
if (status.value === false) {
videoUrl.value = `data:video/mp4;base64,${url}`;
// const no_voice = downLoadUrl(sessionStorage.getItem("patientDummyVideo"));
const video = document.createElement("video");
video.src = `data:video/mp4;base64,${url}`;
video.src = `data:video/mp4;base64, ${patientDummyVideo.value}`;
video.controls = false;
video.autoplay = true;
video.style.width = "100%";
video.style.height = "100%";
video.style.objectFit = "cover";
const myAuto = document.getElementById("myAudio");
audioUrl.value = `data:audio/mp3;base64, ${url}`;
await myAuto.load();
video.addEventListener("canplaythrough", () => {
//
document.getElementById("video_content").appendChild(video);
status.value = true;
videoFlag.value = true;
myAuto.play();
status.value = true;
});
video.addEventListener("ended", () => {
//
myAuto.addEventListener("ended", function () {
useConsultationStoreHooks().changeVoiceFlag(false);
videoFlag.value = false;
status.value = false;
video.remove();
//
});
} else {
setTimeout(() => {
@ -51,9 +89,16 @@ defineExpose({
}
});
onMounted(() => {
onMounted(async () => {
const id = sessionStorage.getItem("patientSilentVideo");
patientSilentVideo.value = downLoadUrl(id);
patientDummyVideo.value = downLoadUrl(
sessionStorage.getItem("patientDummyVideo")
);
const res: any = await loadFileBase64({
fileId: sessionStorage.getItem("patientDummyVideo")
});
patientDummyVideo.value = res.data;
});
// const handleVideoEnded = () => {
// // videoFlag.value = false;
@ -63,7 +108,7 @@ onMounted(() => {
<template>
<div class="PeopleVideo">
<!-- <img v-show="!videoFlag" :src="peopleImg" alt="" /> -->
<audio :src="audioUrl" id="myAudio" hidden="true" />
<div class="video_content" id="video_content">
<video
v-show="!videoFlag"
@ -74,6 +119,17 @@ onMounted(() => {
autoplay
:controls="false"
/>
<!-- <transition name="fade">
<video
v-if="videoFlag"
muted
loop
:src="patientDummyVideo"
autoplay
:controls="false"
/>
</transition> -->
</div>
</div>
</template>

@ -108,8 +108,10 @@ onBeforeUnmount(() => {
</template>
<style lang="scss" scoped>
.voiceInquiry {
position: fixed;
bottom: 66px;
position: absolute;
right: 0;
bottom: 24px;
z-index: 99999;
display: flex;
justify-content: center;
width: 500px;

@ -6,6 +6,8 @@ import AssistInspect from "./AssistInspect/index.vue";
import ConfirmDiagnosis from "./ConfirmDiagnosis/index.vue";
import ConsultationReview from "./ConsultationReview/index.vue";
import ConsultationEvaluation from "./ConsultationEvaluation/index.vue";
import ConsultationRecords from "./ConsultationRecords/index.vue";
import TipIcon from "@/assets/tip.png";
// import Evaluate from "./Evaluate/index.vue";
import { useConsultationStoreHooks } from "@/store/modules/consultation";
import KnowledgeGraph from "./KnowledgeGraph/index.vue";
@ -83,6 +85,7 @@ onMounted(async () => {
<div class="first_item card_item_img" />
<span>问诊回顾 </span>
</div>
<div
v-if="inspectSatus === '0'"
class="card_item"
@ -110,6 +113,7 @@ onMounted(async () => {
<div class="evaluate_item card_item_img" />
<span>问诊评估</span>
</div>
<div
@click="changeIndex(5)"
v-if="inspectSatus === '2'"
@ -119,8 +123,18 @@ onMounted(async () => {
<div class="knowledge_graph card_item_img" />
<span>知识图谱</span>
</div>
<div
@click="changeIndex(6)"
v-if="inspectSatus === '2'"
:class="[activedIndex === 6 ? 'actived' : '']"
class="card_item record"
>
<div class="record_item card_item_img" />
<span>问诊反馈</span>
<img :src="TipIcon" alt="" />
</div>
</div>
<div class="main_content">
<div :class="[activedIndex === 0 ? 'first_content' : 'main_content']">
<FirstConsultation
v-if="inspectSatus === '0'"
v-show="activedIndex === 0"
@ -134,6 +148,7 @@ onMounted(async () => {
<!-- <Evaluate v-if="activedIndex === 4" /> -->
<ConsultationEvaluation v-if="activedIndex === 4" />
<KnowledgeGraph v-if="activedIndex === 5" />
<ConsultationRecords v-if="activedIndex === 6" />
</div>
</div>
</div>
@ -202,6 +217,10 @@ onMounted(async () => {
background-image: url("../../assets/newInquiry/tab/evaluate.png");
}
.record_item {
background-image: url("../../assets/newInquiry/tab/record.png");
}
.knowledge_graph {
background-image: url("../../assets/newInquiry/tab/graph.png");
}
@ -223,6 +242,10 @@ onMounted(async () => {
background-image: url("../../assets/newInquiry/tab/act_evaluate.png");
}
.record_item {
background-image: url("../../assets/newInquiry/tab/act_record.png");
}
.confirm_item {
background-image: url("../../assets/newInquiry/tab/act_confirm_icon.png");
}
@ -240,6 +263,26 @@ onMounted(async () => {
background-image: url("../../assets/newInquiry/main_bg.png");
background-size: 100% 100%;
}
.first_content {
flex: 1;
// min-width: 1760px;
margin-bottom: 24px;
background-image: url("../../assets/newInquiry/main_bg.png");
background-size: 100% 100%;
}
}
.record {
position: relative;
img {
position: absolute;
top: -14px;
right: -13px;
width: 50px;
height: 50px;
}
}
}
</style>

@ -0,0 +1,290 @@
<script setup lang="ts">
import { nextTick, reactive, ref } from "vue";
import { ElMessage, FormInstance, UploadProps } from "element-plus";
import { Plus, Delete } from "@element-plus/icons-vue";
import { message } from "@/utils/message";
// import { useRoute } from "vue-router";
import { getToken } from "@/utils/auth";
defineOptions({
name: "AddEdit"
});
const fileList = ref([]);
const isEditFlag = ref(false);
const id = ref("");
const dialogVisible = ref(false);
const formData = reactive({
iconBase64: "",
directoryDesc: ""
});
const ruleFormRef = ref<FormInstance>();
const rules = {
iconBase64: [{ required: true, message: "请选择", trigger: "change" }],
directoryDesc: [{ required: true, message: "请输入", trigger: "change" }]
};
const handleSuccess: UploadProps["onSuccess"] = response => {
formData.iconBase64 = `/virtual-patient-manage/fileManage/downloadFile?fileId=${response.data.id}`;
};
const handleRemove = () => {
formData.iconBase64 = "";
fileList.value = [];
};
const beforeUpload: UploadProps["beforeUpload"] = async rawFile => {
// png|jpg 10M
if (
rawFile.type !== "image/png" ||
rawFile.type == "image/jpg" ||
rawFile.type == "image/jpeg"
) {
ElMessage.error("上传文件格式务必PNG|JPG|JPEG");
return false;
} else if (rawFile.size / 1024 / 1024 > 10) {
ElMessage.error("图片大小不能大于10M");
return false;
}
return true;
};
defineExpose({
async open(item) {
dialogVisible.value = true;
await nextTick();
if (item) {
for (const key in item) {
// eslint-disable-next-line no-prototype-builtins
if (formData.hasOwnProperty(key)) {
formData[key] = item[key];
}
}
isEditFlag.value = true;
id.value = item.id;
}
}
});
const resetForm = () => {
ruleFormRef.value.resetFields();
};
const closeDialog = () => {
dialogVisible.value = false;
isEditFlag.value = false;
resetForm();
};
const emit = defineEmits(["update"]);
const reset = () => {
if (isEditFlag.value) {
ruleFormRef.value.resetFields([
"diagnosticCriteria",
"diagnosisAssessmentFlag",
"requireCheckFlag",
"expectedDiagnosisResult",
"normalResult"
]);
} else {
ruleFormRef.value.resetFields();
}
// refWangEditor.value.valueHtml = "";
};
const save = (formEl: FormInstance | undefined) => {
formEl.validate(async (valid, fields) => {
if (valid) {
// formData.result = refWangEditor.value.valueHtml;
// const params = {
// ...formData,
// result: refWangEditor.value.valueHtml,
// diseaseId: route.query.id
// };
if (isEditFlag.value) {
// const res: any = await updateSupportInspect({
// ...params,
// id: id.value
// });
if (res.code === 200) {
message("修改成功", { type: "success" });
id.value = "";
}
} else {
// const res: any = await addSupportInspect(params);
// if (res.code === 200) {
// message("", { type: "success" });
// }
}
dialogVisible.value = false;
emit("update");
} else {
return fields;
}
});
};
</script>
<template>
<div>
<el-drawer
:size="800"
append-to-body
v-model="dialogVisible"
:show-close="false"
:with-header="false"
:before-close="closeDialog"
custom-class="AddEdit"
>
<div class="AddEdit">
<div class="header-title">
<div class="tip" />
<span>生成数字人</span>
</div>
<div class="line" />
<el-form
ref="ruleFormRef"
:model="formData"
:rules="rules"
label-width="120px"
>
<el-form-item label="选择数字人形象" prop="code">
<div class="upload_img">
<el-upload
:limit="1"
:headers="{
token: getToken()
}"
action="/virtual-patient-manage/fileManage/uploadFile"
list-type="picture-card"
:file-list="fileList"
:on-success="handleSuccess"
:before-upload="beforeUpload"
:class="{ hide: formData.iconBase64 !== '' }"
>
<el-icon><Plus /></el-icon>
<template #file="{ file }">
<div>
<img
class="el-upload-list__item-thumbnail"
:src="formData.iconBase64"
alt=""
/>
<span class="el-upload-list__item-actions">
<span
class="el-upload-list__item-delete"
@click="handleRemove(file)"
>
<el-icon><Delete /></el-icon>
</span>
</span>
</div>
</template>
</el-upload>
<div class="tip">仅支持JPGPNG格式图片尺寸420*746</div>
</div>
</el-form-item>
<el-form-item label="说明 " prop="directoryDesc">
<el-input
:rows="4"
:maxLength="500"
type="textarea"
placeholder="请输入"
v-model="formData.directoryDesc"
/>
</el-form-item>
</el-form>
</div>
<template #footer>
<div class="footer_btn">
<div class="reset" @click="reset()"></div>
<div class="main" @click="save(ruleFormRef)"></div>
</div>
</template>
</el-drawer>
</div>
</template>
<style lang="scss" scoped>
.AddEdit {
:deep(.el-form-item__label) {
font-weight: 400;
color: #333;
}
:deep(.hide .el-upload--picture-card) {
display: none;
}
.header-title {
display: flex;
align-items: center;
// border-left: 6px solid #4287ff;
font-size: 20px;
font-weight: bold;
color: #2b3f54;
.tip {
width: 6px;
height: 20px;
margin-right: 10px;
line-height: 20px;
background: #4287ff;
}
}
.line {
position: relative;
left: -20px;
width: 755px;
height: 1px;
margin: 24px 0;
background: rgb(91 139 255 / 30%);
}
.footer_btn {
display: flex;
align-items: center;
justify-content: flex-end;
margin-top: 16px;
.reset {
width: 188px;
height: 48px;
margin-right: 24px;
font-size: 16px;
font-weight: 400;
line-height: 48px;
color: #4287ff;
text-align: center;
cursor: pointer;
background: #fff;
border: 1px solid #4287ff;
border-radius: 6px;
}
.main {
width: 188px;
height: 48px;
font-size: 16px;
line-height: 48px;
color: #fff;
text-align: center;
cursor: pointer;
background: #4287ff;
border: 1px solid #4287ff;
border-radius: 6px;
}
}
.upload_img {
position: relative;
width: 100%;
.tip {
position: absolute;
top: 50px;
left: 200px;
font-size: 12px;
font-weight: 400;
color: #b4b4b4;
}
}
}
</style>

@ -0,0 +1,133 @@
<script setup lang="ts">
import { onMounted, ref } from "vue";
import AddEdit from "./addEdit.vue";
import { Edit, Delete } from "@element-plus/icons-vue";
import { downLoadUrl } from "@/utils/auth";
const dataList = ref([]);
const activedId = ref("");
const AddEditRef = ref();
const add = () => {
AddEditRef.value.open();
};
const onMouseenter = id => {
activedId.value = id;
};
const onMouseleave = () => {
activedId.value = "";
};
const handleCommand = async (e: any) => {
if (e === "edit") {
// EditMaterialsRef.value.open(0, item);
} else {
// const res: any = await deleteMaterial({
// id: item.id
// });
// if (res.code === 200) {
// message("", { type: "success" });
// getData();
// }
}
};
const getData = () => {};
onMounted(() => {
getData();
});
</script>
<template>
<div class="digitalHuman main-table">
<div class="main-table-title">
<div class="title">
<div class="line" />
<span> 数字人生成器 </span>
</div>
</div>
<el-row class="mb-6">
<el-button size="large" class="btn" @click="add" type="primary"
>生成数字人</el-button
>
</el-row>
<div v-show="dataList.length > 0" class="img_card_list">
<div
class="img_card_item"
v-for="(item, index) in dataList"
:key="index"
@mouseenter.prevent="onMouseenter(item.id)"
@mouseleave.prevent="onMouseleave()"
>
<div class="folder_img">
<img :src="downLoadUrl(item.fileResourceId)" alt="" />
</div>
<div :title="item.materialName" class="name">
{{ item.materialName }}
</div>
<el-dropdown
@command="e => handleCommand(e, item)"
trigger="click"
class="icon"
>
<moreIcon v-show="activedId === item.id" />
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item command="edit" :icon="Edit">
编辑
</el-dropdown-item>
<el-dropdown-item command="del" :icon="Delete">
删除
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</div>
<AddEdit ref="AddEditRef" />
</div>
</template>
<style lang="scss" scoped>
.digitalHuman {
.img_card_list {
display: flex;
flex-wrap: wrap;
.img_card_item {
position: relative;
width: 190px;
height: 230px;
margin-right: 16px;
margin-bottom: 16px;
cursor: pointer;
background: #fff;
border-radius: 0 0 12px 12px;
box-shadow: 0 2px 4px 0 rgb(0 0 0 / 8%);
.icon {
position: absolute;
top: 12px;
right: 12px;
}
.folder_img {
display: flex;
align-items: center;
justify-content: center;
height: 190px;
background: #f5f5f5;
img {
width: 130px;
height: 130px;
}
}
.name {
width: 200px;
padding: 8px 16px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
}
}
</style>

@ -13,10 +13,14 @@ import bg from "../../assets/login/login_bg.png";
import { useRenderIcon } from "@/components/ReIcon/src/hooks";
// import update from "./components/update.vue";
import { ref, reactive, onMounted, onBeforeUnmount, nextTick } from "vue";
import registerIcon from "@/assets/login/register.png";
import { getRegister, changePassWord } from "@/api/user";
import Lock from "@iconify-icons/icon-park-outline/lock";
import User from "@iconify-icons/icon-park-outline/user";
import PreviewClose from "@iconify-icons/icon-park-outline/preview-close";
import PreviewOpen from "@iconify-icons/icon-park-outline/preview-open";
import IdCard from "@iconify-icons/icon-park-outline/id-card";
// import InviteCode from "@iconify-icons/icon-park-outline/user-to-user-transmission";
defineOptions({
name: "Login"
@ -24,11 +28,11 @@ defineOptions({
const router = useRouter();
const loading = ref(false);
const ruleFormRef = ref<FormInstance>();
const registerFormRef = ref<FormInstance>();
const modifyFormRef = ref<FormInstance>();
const checked = ref(false);
// const currentPage = computed(() => {
// return useUserStoreHook().currentPage;
// });
const cardType = ref(1);
const { initStorage } = useLayout();
initStorage();
@ -40,7 +44,18 @@ const ruleForm = reactive({
username: "",
password: ""
});
const registerForm = reactive({
account: "",
name: "",
password: "",
newPassword: ""
});
const modifyForm = reactive({
account: "",
name: "",
password: "",
newPassword: ""
});
const onLogin = async (formEl: FormInstance | undefined) => {
loading.value = true;
if (!formEl) return;
@ -78,6 +93,46 @@ const onLogin = async (formEl: FormInstance | undefined) => {
}
});
};
const register = async (formEl: FormInstance | undefined) => {
loading.value = true;
if (!formEl) return;
await formEl.validate(async (valid, fields) => {
if (valid) {
const res: any = await getRegister({
account: registerForm.account,
name: registerForm.name,
password: registerForm.password
});
loading.value = false;
if (res.code === 200) {
changeCardType(4);
}
} else {
loading.value = false;
return fields;
}
});
};
const onModify = async (formEl: FormInstance | undefined) => {
loading.value = true;
if (!formEl) return;
await formEl.validate(async (valid, fields) => {
if (valid) {
const res: any = await changePassWord({
account: modifyForm.account,
name: modifyForm.name,
password: modifyForm.password
});
loading.value = false;
if (res.code === 200) {
changeCardType(5);
}
} else {
loading.value = false;
return fields;
}
});
};
const passwordType = ref("password");
const refInput = ref();
/** 使用公共函数,避免`removeEventListener`失效 */
@ -98,6 +153,23 @@ function showPass() {
});
}
const changeCardType = val => {
cardType.value = val;
};
const validateConfirmPassword = (rule, value, callback) => {
if (value !== registerForm.password) {
callback(new Error("请再次输入密码以确保一致,不能留空"));
} else {
callback();
}
};
const validatePassword = (rule, value, callback) => {
if (value !== modifyForm.password) {
callback(new Error("请再次输入密码以确保一致,不能留空"));
} else {
callback();
}
};
onMounted(() => {
window.document.addEventListener("keypress", onkeypress);
});
@ -116,7 +188,7 @@ onBeforeUnmount(() => {
<span class="systeam-name">虚拟病人系统</span>
<span class="desc">Welcome to the Virtual Patient System</span>
</div>
<div class="login-box">
<div v-if="cardType === 1" class="login-box">
<div class="login-form">
<div class="top">
<p class="title">欢迎登录虚拟病人系统</p>
@ -193,6 +265,7 @@ onBeforeUnmount(() => {
>
{{ "忘记密码?" }}
</el-button> -->
<div class="btn-color" @click="changeCardType(3)"></div>
</div>
<el-button
class="w-full mt-9 login-btn"
@ -206,8 +279,273 @@ onBeforeUnmount(() => {
</el-button>
</Motion>
</el-form>
<!-- 忘记密码 -->
<!-- <update v-if="currentPage === 4" /> -->
<div @click="changeCardType(2)" class="desc">还没账号去注册</div>
</div>
</div>
<div v-if="cardType === 2" class="register-box">
<div class="login-form">
<div class="top">
<p class="title">注册账号</p>
<p class="top_desc">Sign up for an to account</p>
</div>
<el-form ref="registerFormRef" :model="registerForm" size="large">
<Motion :delay="100">
<el-form-item
:rules="[
{
required: true,
message: '请使用中文填写您的姓名6字以内',
trigger: 'blur'
},
{
pattern: /^[\u4e00-\u9fa5]+$/,
message: '请使用中文填写您的姓名6字以内',
trigger: 'change'
}
]"
prop="name"
>
<el-input
maxlength="6"
style="height: 60px; font-size: 16px"
v-model="registerForm.name"
placeholder="请输入姓名"
:prefix-icon="useRenderIcon(IdCard)"
/>
</el-form-item>
</Motion>
<Motion :delay="100">
<el-form-item
:rules="[
{
required: true,
message: '请输入账号',
trigger: 'blur'
},
{
pattern: /^[a-zA-Z0-9]{6,18}$/,
message: '使用6至18个英文字母或数字',
trigger: 'change'
}
]"
prop="account"
>
<el-input
autocomplete="off"
style="height: 60px; font-size: 16px"
v-model="registerForm.account"
placeholder="请输入账号"
:prefix-icon="useRenderIcon(User)"
/>
</el-form-item>
</Motion>
<Motion :delay="150">
<el-form-item
prop="password"
:rules="[
{
required: true,
message: '请输入密码',
trigger: 'blur'
},
{
pattern: /^(?![\u4e00-\u9fa5\s])[\x21-\x7e]{6,18}$/,
message: '密码6-18位 不包含中文特殊字符和空格',
trigger: 'change'
}
]"
>
<el-input
type="password"
autocomplete="new-password"
style="height: 60px; font-size: 16px"
v-model="registerForm.password"
placeholder="请输入密码"
:prefix-icon="useRenderIcon(Lock)"
/>
</el-form-item>
</Motion>
<Motion :delay="150">
<el-form-item
prop="newPassword"
:rules="[
{
required: true,
message: '请再次输入密码',
trigger: 'blur'
},
{
pattern: /^(?![\u4e00-\u9fa5\s])[\x21-\x7e]{6,18}$/,
message: '密码6-18位 不包含中文特殊字符和空格',
trigger: 'change'
},
{ validator: validateConfirmPassword, trigger: 'blur' }
]"
>
<el-input
style="height: 60px; font-size: 16px"
type="password"
autocomplete="new-password"
v-model="registerForm.newPassword"
placeholder="请再次输入密码"
:prefix-icon="useRenderIcon(Lock)"
/>
</el-form-item>
</Motion>
<Motion :delay="250">
<el-button
class="w-full mt-9 login-btn"
size="large"
type="primary"
color="rgba(66, 135, 255, 1)"
:loading="loading"
@click="register(registerFormRef)"
>
确定
</el-button>
</Motion>
</el-form>
<div @click="changeCardType(1)" class="desc">已有账号去登录</div>
</div>
</div>
<div v-if="cardType === 3" class="login-box" style="height: 560px">
<div class="login-form">
<div class="top">
<p class="title" style="margin-bottom: 52px">忘记密码</p>
<!-- <p class="top_desc" style="font-size: 14px">
为了您的账户安全请重新设置位数密码
</p> -->
</div>
<el-form ref="modifyFormRef" :model="modifyForm" size="large">
<Motion :delay="100">
<el-form-item
:rules="[
{
required: true,
message: '请输入账号',
trigger: 'blur'
}
]"
prop="account"
>
<el-input
style="height: 60px; font-size: 16px"
v-model="modifyForm.account"
placeholder="请输入账号"
:prefix-icon="useRenderIcon(User)"
/>
</el-form-item>
</Motion>
<Motion :delay="150">
<el-form-item
prop="password"
:rules="[
{
required: true,
message: '请输入新密码',
trigger: 'blur'
},
{
pattern: /^(?![\u4e00-\u9fa5\s])[\x21-\x7e]{6,18}$/,
message: '密码6-18位 不包含中文特殊字符和空格',
trigger: 'change'
}
]"
>
<el-input
type="password"
autocomplete="new-password"
style="height: 60px; font-size: 16px"
v-model="modifyForm.password"
placeholder="请输入密码"
:prefix-icon="useRenderIcon(Lock)"
/>
</el-form-item>
</Motion>
<Motion :delay="150">
<el-form-item
prop="newPassword"
:rules="[
{
required: true,
message: '请再次输入新密码',
trigger: 'blur'
},
{
pattern: /^(?![\u4e00-\u9fa5\s])[\x21-\x7e]{6,18}$/,
message: '密码6-18位 不包含中文特殊字符和空格',
trigger: 'change'
},
{ validator: validatePassword, trigger: 'blur' }
]"
>
<el-input
type="password"
autocomplete="new-password"
style="height: 60px; font-size: 16px"
v-model="modifyForm.newPassword"
placeholder="请再次输入新密码"
:prefix-icon="useRenderIcon(Lock)"
/>
</el-form-item>
</Motion>
<Motion :delay="250">
<el-button
class="w-full mt-9 login-btn"
size="large"
type="primary"
color="rgba(66, 135, 255, 1)"
:loading="loading"
@click="onModify(modifyFormRef)"
>
确定
</el-button>
</Motion>
</el-form>
<div @click="changeCardType(1)" class="desc">已有账号去登录</div>
</div>
</div>
<div v-if="cardType === 4" class="login-box" style="height: 546px">
<div class="content">
<img :src="registerIcon" alt="" />
<div class="content_top">
<p class="content_top_title">注册成功</p>
<p class="content_top_desc">
已注册成功您可以使用账号密码登录系统
</p>
</div>
<el-button
style="margin-top: 130px"
class="w-full login-btn"
size="large"
type="primary"
color="rgba(66, 135, 255, 1)"
@click="changeCardType(1)"
>
去登录
</el-button>
</div>
</div>
<div v-if="cardType === 5" class="login-box" style="height: 546px">
<div class="content">
<img :src="registerIcon" alt="" />
<div class="content_top">
<p class="content_top_title">重置成功</p>
<p class="content_top_desc">您可以重新登录系统验证您的新密码</p>
</div>
<el-button
style="margin-top: 130px"
class="w-full login-btn"
size="large"
type="primary"
color="rgba(66, 135, 255, 1)"
@click="changeCardType(1)"
>
重新登录
</el-button>
</div>
</div>
</div>
@ -233,12 +571,16 @@ onBeforeUnmount(() => {
}
.btn-color {
color: #1c0d82;
font-size: 16px;
color: #4287ff;
cursor: pointer;
}
.btn-color:hover {
color: #1c0d82;
opacity: 0.5;
.desc {
margin-top: 16px;
font-size: 14px;
color: #787878;
cursor: pointer;
}
.el-input__icon {
@ -263,7 +605,8 @@ onBeforeUnmount(() => {
}
}
.login-box {
.login-box,
.register-box {
.top {
.title {
font-size: 24px;
@ -278,5 +621,46 @@ onBeforeUnmount(() => {
color: #666;
}
}
.content {
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
padding: 35px 40px 0;
img {
width: 137px;
height: 94px;
margin-bottom: 40px;
}
.content_top {
.content_top_title {
font-size: 24px;
color: #333;
}
.content_top_desc {
margin-top: 8px;
font-size: 14px;
color: #666;
}
}
}
}
.register-box {
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
width: 500px;
height: 665px;
padding-top: 65px;
margin-left: 160px;
text-align: center;
background: #fff;
border-radius: 10px;
}
</style>

@ -14,6 +14,7 @@ import {
import { getUserInfo } from "@/utils/auth";
import { useConsultationStoreHooks } from "@/store/modules/consultation";
import { creatDiagnosisProcesse } from "@/api/inquiry";
// import { message } from "@/utils/message";
import { downLoadUrl } from "@/utils/auth";
import { ElMessageBox } from "element-plus";
@ -28,6 +29,7 @@ const addCase = () => {
caseList.value = medicalRecList.value;
};
const goBack = () => {
console.log("111", userPagination);
addFlag.value = false;
caseList.value = diagnoseProcessList.value;
};
@ -51,6 +53,7 @@ const openCase = async item => {
createProcess(item);
}
sessionStorage.setItem("patientSilentVideo", item.patientSilentVideo);
sessionStorage.setItem("patientDummyVideo", item.patientDummyVideo);
// } else {
// message("", { type: "warning" });
// }
@ -88,12 +91,13 @@ const getDiagnoseProcessPageList = async () => {
userId: JSON.parse(userInfo).id
};
const res: any = await queryDiagnoseProcessPageList(params);
if (res?.code === 200) {
userPagination.total = res.data?.total;
caseList.value = res.data?.records;
userPagination.total = res.data.total;
caseList.value = res.data.records;
diagnoseProcessList.value = res.data.records;
userPagination.total = res.data.total;
diagnoseProcessList.value = res.data?.records;
userPagination.total = res.data?.total;
}
};
const getMedicalRecPageList = async () => {
const params = {
@ -101,14 +105,17 @@ const getMedicalRecPageList = async () => {
pageSize: casePagination.pageSize
};
const res: any = await queryMedicalRecPageList(params);
medicalRecList.value = res.data.records;
casePagination.total = res.data.total;
if (addFlag.value === true) {
caseList.value = medicalRecList.value;
if (res?.code === 200) {
medicalRecList.value = res.data.records;
casePagination.total = res.data.total;
if (addFlag.value === true) {
caseList.value = medicalRecList.value;
}
}
};
const handleUserChange = val => {
userPagination.currentPage = val;
console.log("111", userPagination);
getDiagnoseProcessPageList();
};
const handleCaseChange = val => {
@ -214,6 +221,7 @@ onMounted(() => {
</div>
<div class="footer">
<el-pagination
:current-page="userPagination.currentPage"
v-if="userPagination.total > 11 && !addFlag"
@current-change="handleUserChange"
:hide-on-single-page="true"
@ -224,6 +232,7 @@ onMounted(() => {
class="mt-4"
/>
<el-pagination
:current-page="casePagination.currentPage"
v-if="casePagination.total > 11 && addFlag"
@current-change="handleCaseChange"
:hide-on-single-page="true"
@ -310,6 +319,8 @@ onMounted(() => {
display: flex;
justify-content: center;
margin-top: 80px;
margin-bottom: 32px;
overflow: auto;
.content {
width: 1200px;

Loading…
Cancel
Save