本周主要完成了三个任务
一、患者基础信息的查询
1.前后端接口联调
(1)患者基础信息解密
(2)患者基础信息修改
2.translate翻译
3.弹窗组件的封装
子组件(弹框组件):
<template>
<a-modal
v-model:visible="localVisible"
:title="null"
:confirm-loading="loading"
width="600px"
:style="{ top: '200px' }"
@cancel="onCancel"
>
<div class="modal-header">
<div class="modal-title">
<span>{{ translate('Patient Basic Information') }}</span>
<a-button
v-if="hasAuth(['patient-details-edit', 'button', 'patient-details'])"
type="link"
@click="toggleEdit"
style="background-color: white; padding: 4px 15px"
>
<EditOutlined />
</a-button>
</div>
</div>
<a-form layout="horizontal" :label-col="{ span: 6 }" :wrapper-col="{ span: 18 }">
<a-form-item :label="translate('patient')" required>
<a-input
v-model:value="patientInfo.name"
:disabled="!editMode"
:maxlength="50"
:placeholder="editMode ? translate('pleaseEnter') : ''"
allow-clear
/>
</a-form-item>
<a-form-item :label="translate('Gender')" required>
<a-select
v-model:value="patientInfo.gender"
:disabled="!editMode"
style="width: 100%"
:placeholder="editMode ? translate('pleaseSelect') : ''"
>
<a-select-option :value="1">{{ translate('Male') }}</a-select-option>
<a-select-option :value="2">{{ translate('Female') }}</a-select-option>
</a-select>
</a-form-item>
<a-form-item :label="translate('birthday')" required>
<a-date-picker
v-model:value="patientInfo.birthday"
:disabled="!editMode"
format="MM-DD-YYYY"
valueFormat="YYYY-MM-DD"
:disabled-date="disabledDate"
style="width: 100%"
:placeholder="editMode ? translate('pleaseSelect') : ''"
/>
</a-form-item>
</a-form>
<template #footer>
<a-button v-if="editMode" @click="handleCancel">
{{ translate('cancel') }}
</a-button>
<a-button v-if="editMode" type="primary" :loading="loading" @click="savePatientInfo">
{{ translate('save') }}
</a-button>
</template>
</a-modal>
</template>
<script lang="ts">
import { defineComponent, ref, reactive, watch } from 'vue'
import { EditOutlined } from '@ant-design/icons-vue'
import { useLang } from '@/hooks'
import { hasAuth } from '@/directives/auth'
import { message } from 'ant-design-vue'
import { editBasicInfo } from '@/api/case'
import dayjs, { Dayjs } from 'dayjs'
export default defineComponent({
components: {
EditOutlined
},
props: {
visible: Boolean,
patientData: Object
},
emits: ['update:visible', 'saved'],
setup(props, { emit }) {
const { translate } = useLang('cases', 'model')
const loading = ref(false)
const editMode = ref(false)
const localVisible = ref(props.visible)
//监听props.visible
watch(
() => props.visible,
(newValue) => {
localVisible.value = newValue
}
)
const patientInfo = reactive({
name: '',
gender: null as number | null,
birthday: '',
pds_code: '',
patient_code: ''
})
const originalPatientInfo = ref({
name: '',
gender: null as number | null,
birthday: '',
pds_code: '',
patient_code: ''
})
watch(
() => props.patientData,
(newVal) => {
if (newVal) {
if (newVal.gender === 'male') {
newVal.gender = 1
} else if (newVal.gender === 'female') {
newVal.gender = 2
}
patientInfo.name = newVal.name || ''
patientInfo.gender = newVal.gender || ''
patientInfo.birthday = newVal.birthday || null
patientInfo.pds_code = newVal.pds_code || ''
patientInfo.patient_code = newVal.patient_code || ''
Object.assign(originalPatientInfo.value, patientInfo)
}
},
{ immediate: true, deep: true }
)
const toggleEdit = () => {
editMode.value = true
}
const savePatientInfo = async () => {
if (!patientInfo.name || !patientInfo.gender || !patientInfo.birthday) {
message.error(translate('fillAllRequiredFields'))
return
}
loading.value = true
try {
const dataToSave = {
pds_code: patientInfo.pds_code,
name: patientInfo.name,
gender: patientInfo.gender,
birthday: patientInfo.birthday,
patient_code: patientInfo.patient_code
}
const response = await editBasicInfo(dataToSave)
if (response.code === 0) {
message.success(translate('operationSuccess'))
editMode.value = false
emit('saved', patientInfo)
emit('update:visible', false)
} else {
message.error(translate('operationFailed'))
}
} catch (error) {
console.error('Failed to save patient info:', error)
message.error(translate('operationFailed'))
} finally {
loading.value = false
}
}
const handleCancel = () => {
Object.assign(patientInfo, originalPatientInfo.value)
// 切换回只读模式
editMode.value = false
}
const disabledDate = (current: Dayjs) => {
// 设置最早可选日期,120年前
const earliestDate = dayjs().subtract(120, 'years')
// 获取今天的日期
const today = dayjs().endOf('day')
// 禁用未来的日期和早于120年前的日期
return current > today || current < earliestDate
}
const onCancel = () => {
handleCancel()
emit('update:visible', false)
}
return {
loading,
editMode,
patientInfo,
localVisible,
translate,
hasAuth,
toggleEdit,
handleCancel,
savePatientInfo,
disabledDate,
onCancel
}
}
})
</script>
<style scoped>
.modal-header {
margin: -24px -24px 24px;
}
.modal-title {
display: flex;
align-items: center;
padding: 16px 24px;
border-bottom: 1px solid #f0f0f0;
}
.modal-title span {
font-size: 16px;
font-weight: 500;
color: rgba(0, 0, 0, 0.85);
}
</style>
父组件使用子组件方式:
<PatientInfoModal
v-model:visible="patientModal.visible"
:patient-data="patientModal"
@saved="handlePatientInfoSaved"
/>
注意:子组件的关闭显示的变量由父组件控制,父组件传递对应的visible给子组件,子组件使用watch监听对应的props.visible,当点击子组件的叉号希望关闭弹窗时,子组件触发对应的父组件update:visible
为什么不需要 defineProps 和 defineEmits:
在代码中,组件是使用 defineComponent 定义的,这是 Vue 3 的选项式 API。在这种情况下,props 和 emits 是在组件选项中定义的。
4.开发过程中的注意事项
(1)将组件放到对应的文件夹下,先从index.ts中import导入,统一export导出后,然后再统一的导入对应的文件夹下的index.ts;
(2)git分支:
包括一个自己开发的feature分支,合并到develop分支,develop分支不要合并到任何分支(develop分支只出不进);通过Jenkins发布到dev环境测试,没问题后,将feature分支合并到release分支,后端提测。
二、vite学习
1.vite、webpack、rollup区别
| 工具 | 核心优势 | 适用场景 | 缺点 |
|---|---|---|---|
| Vite | 开发速度极快,开箱即用 | 现代框架项目、快速原型开发 | 生产依赖 Rollup,生态较新 |
| Webpack | 功能全面,生态强大 | 复杂应用、企业级项目 | 配置复杂,性能较低 |
| Rollup | 高效的 Tree-shaking,适合库打包 | JS 库/工具开发 | 不适合复杂应用构建 |
2.vite不会完全替代webpack的意义:
vite是基于es modules的,侧重点不一样,webpack更多的关注兼容性,而vite关注浏览器的开发体验; webpack支持多种模块化,他一开始必须要统一模块化代码,所以意味着他需要将所有的依赖全部读一遍。二者的侧重点不一样。
3.传统的构建工具(如 Webpack、Rollup)在默认情况下会将所有依赖的模块打包成一个或多个 bundle 文件
传统的打包:
Vite 通过在一开始将应用中的模块区分为 依赖 和 源码 两类,改进了开发服务器启动时间。
-
依赖 大多为在开发时不会变动的纯 JavaScript。一些较大的依赖(例如有上百个模块的组件库)处理的代价也很高。依赖也通常会存在多种模块化格式(例如 ESM 或者 CommonJS)。
Vite 将会使用 esbuild 预构建依赖。esbuild 使用 Go 编写,并且比以 JavaScript 编写的打包器预构建依赖快 10-100 倍。
-
源码 通常包含一些并非直接是 JavaScript 的文件,需要转换(例如 JSX,CSS 或者 Vue/Svelte 组件),时常会被编辑。同时,并不是所有的源码都需要同时被加载(例如基于路由拆分的代码模块)。
Vite 以 原生 ESM 方式提供源码。这实际上是让浏览器接管了打包程序的部分工作:Vite 只需要在浏览器请求源码时进行转换并按需提供源码。根据情景动态导入代码,即只在当前屏幕上实际使用时才会被处理。
4.传统的打包工具(如 Webpack、Rollup)和 Vite 在构建方式、开发体验、生产优化等方面有显著区别。以下是它们的核心差异对比:
(1) 开发环境对比
传统打包工具(Webpack/Rollup)
全量打包:
- 启动时分析所有依赖,生成完整的
bundle.js(即使只改一行代码)。 - 冷启动慢,尤其大型项目可能需要几十秒甚至更久。
HMR(热更新) :
- 修改代码后,Webpack 重新构建变动的模块,但仍有延迟。
开发体验瓶颈:
- 项目越大,启动和热更新越慢。
Vite
基于原生 ESM(ES Modules) :
- 不打包,浏览器直接加载 ES Modules,按需编译当前页面所需文件。
- 冷启动极快(毫秒级),与项目规模无关。
按需编译:
- 仅编译当前访问的页面文件,动态加载依赖(如路由懒加载)。
HMR 超快:
- 利用浏览器缓存和原生 ESM,热更新几乎无延迟。
兼容性要求:
- 依赖现代浏览器支持 ESM,旧项目可能需要调整代码。
(2)生产环境对比
传统打包工具(Webpack/Rollup)
全量打包优化:
- 使用 Babel 降级(ES5)、Tree-shaking、代码压缩(Terser)。
- 生成少量
chunk文件,减少 HTTP 请求。
成熟稳定:
- 适合复杂项目(如 SSR、微前端)。
配置复杂:
- 需要手动优化 Loader、Plugin、Code Splitting。
Vite
默认使用 Rollup 打包:
- 生产构建和传统工具类似,但配置更简单(继承开发环境优化)。
- 仍然支持 Tree-shaking、代码压缩。
更智能的预构建:
- 依赖(
node_modules)会预编译为 ESM,提升缓存利用率。
生态较新:
- 某些 Webpack 插件可能需要替代方案。