|
|
- <template>
- <div class="step-container">
- <el-button v-if="isShowAddStep()" type="primary" @click="addStep" icon="el-icon-plus">添加步骤</el-button>
- <div class="step-list">
- <div v-for="(step, index) in steps" :key="step.id" class="step-list-item">
-
-
- <div class="step-content">
- <span class="step-title">{{ index + 1 }}</span>
- <HandleFormItem type="select" placeholder="请选择" class="step-type-select" :item="stepSelectConfig"
- v-model="step.type" @change="onTypeChange(index)" />
-
- <!-- 根据步骤类型显示对应的表单 -->
- <!-- 根据步骤类型显示对应的表单 -->
- <component class="flex1" :is="getStepComponent(step.type)" :formData="step.formData"
- @update="onFormUpdate(index, $event)" :ref="'stepCompRef_' + index">
- </component>
- <div v-if="templateFillType === 'preFill'" class="step-header-item">
- <el-popconfirm
- @confirm="removeStep(index)"
- title="确定删除当前步骤吗?"
- >
- <el-button type="text" slot="reference" icon="el-icon-delete"
- class="delete-btn"></el-button>
- </el-popconfirm>
- </div>
- </div>
- </div>
- </div>
- </div>
- </template>
-
- <script>
- import { duplicateResource } from '@/utils/index.js';
- import HandleFormItem from './HandleFormItem.vue';
- import Czdd from './StepComponents/ry/czdd.vue';//溶液-操作地点
- import Czhj from './StepComponents/ry/czhj.vue';//溶液-操作方法
- import Xzrq from './StepComponents/ry/xzrq.vue';//溶液-选择容器
- import Jrry from './StepComponents/ry/jrry.vue';//溶液-加入溶液
- import Tpjydd from './StepComponents/ry/tpjydd.vue';//溶液-天平校验(单点)
- import Tpjysd from './StepComponents/ry/tpjysd.vue';//溶液-天平校验(双点)
- import Qywz from './StepComponents/ry/qywz.vue';//溶液-取用物质
- import Clfcz from './StepComponents/ry/clfcz.vue';//溶液-称量(非传值)
- import Clcz from './StepComponents/ry/clcz.vue';//溶液-称量(传值)
- import Bdtj from './StepComponents/ry/bdtj.vue';//溶液-标定(体积)
- import Bdzl from './StepComponents/ry/bdzl.vue';//溶液-标定(质量)
- import Tjphcz from './StepComponents/ry/tjphcz.vue';//溶液-调节PH(传值)
- import Tjphfcz from './StepComponents/ry/tjphfcz.vue';//溶液-调节PH(非传值)
- import Lx from './StepComponents/ry/lx.vue';//溶液-离心
- import Hwhy from './StepComponents/ry/hwhy.vue';//溶液-恒温混匀
- import Zyhy from './StepComponents/ry/zyhy.vue';//溶液-振摇混匀
- import Wxhy from "./StepComponents/ry/wxhy.vue";//溶液-涡旋混匀
- import Ddhy from "./StepComponents/ry/ddhy.vue";//溶液-颠倒混匀
- import Ym from "./StepComponents/ry/ym.vue";//溶液-研磨
- import Jb from "./StepComponents/ry/jb.vue";//溶液-搅拌
- import Jrjb from "./StepComponents/ry/jrjb.vue";//溶液-加热搅拌
- import Cs from "./StepComponents/ry/cs.vue";//溶液-超声
- import Sy from "./StepComponents/ry/sy.vue";//溶液-水浴
- import Dc from "./StepComponents/ry/dc.vue";//溶液-氮吹
- import Jd from "./StepComponents/ry/jd.vue";//溶液-解冻
- import Jz from "./StepComponents/ry/jz.vue";//溶液-静置
- import Glzd from "./StepComponents/ry/glzd.vue";//溶液-过滤(自动)
- import Glsd from "./StepComponents/ry/glsd.vue";//溶液-过滤(手动)
- import Fy from "./StepComponents/ry/fy.vue";//溶液-孵育
- import Qcyy from "./StepComponents/ry/qcyy.vue";//溶液-取出原药
- import Frdrq from "./StepComponents/ry/frdrq.vue";//溶液-复溶(多容器)
- import Fr from "./StepComponents/ry/fr.vue";//溶液-复溶
- import Hb from "./StepComponents/ry/hb.vue";//溶液-合并
- import Rs from "./StepComponents/ry/rs.vue";//溶液-染色
- import Js from "./StepComponents/ry/js.vue";//溶液-计数
- import Mj from "./StepComponents/ry/mj.vue";//溶液-灭菌
- import Fs from "./StepComponents/ry/fs.vue";//溶液-复苏
- import Fb from "./StepComponents/ry/fb.vue";//溶液-封板
-
-
-
- const stepTypes = [
- { label: '操作地点', value: 'czdd' },
- { label: '操作方法', value: 'czhj' },
- { label: '选择容器', value: 'xzrq' },
- { label: '加入溶液', value: 'jrry' },
- { label: '天平校验(单点)', value: 'tpjydd' },
- { label: '天平校验(双点)', value: 'tpjysd' },
- { label: '取用物质', value: 'qywz' },
- { label: '称量(非传值)', value: 'clfcz' },
- { label: '称量(传值)', value: 'clcz' },
- { label: '标定(体积)', value: 'bdtj' },
- { label: '标定(质量)', value: 'bdzl' },
- { label: '调节PH(传值)', value: 'tjphcz' },
- { label: '调节PH(非传值)', value: 'tjphfcz' },
- { label: '离心', value: 'lx' },
- { label: '恒温混匀', value: 'hwhy' },
- { label: '振摇混匀', value: 'zyhy' },
- { label: '涡旋混匀', value: 'wxhy' },
- { label: '颠倒混匀', value: 'ddhy' },
- { label: '研磨', value: 'ym' },
- { label: '搅拌', value: 'jb' },
- { label: '加热搅拌', value: 'jrjb' },
- { label: '超声', value: 'cs' },
- { label: '水浴', value: 'sy' },
- { label: '氮吹', value: 'dc' },
- { label: '解冻', value: 'jd' },
- { label: '静置', value: 'jz' },
- { label: '过滤(自动)', value: 'glzd' },
- { label: '过滤(手动)', value: 'glsd' },
- { label: '孵育', value: 'fy' },
- { label: '取出原药', value: 'qcyy' },
- { label: '复溶(多容器)', value: 'frdrq' },
- { label: '复溶', value: 'fr' },
- { label: '合并', value: 'hb' },
- { label: '染色', value: 'rs' },
- { label: '计数', value: 'js' },
- { label: '灭菌', value: 'mj' },
- { label: '复苏', value: 'fs' },
- { label: '封板', value: 'fb' },
-
- ];
-
- export default {
- inject: ['templateFillType'],
- name: 'Step',
- props: {
- formData: {
- type: Array,
- default: () => []
- }
- },
- data() {
- return {
- stepSelectConfig: {
- options: stepTypes,
- fillType: "preFill",
- placeholder: "请选择步骤类型"
- },
- steps: [],
- stepId: 1,
- componentMap: null
- }
- },
- components: {
- HandleFormItem,
- Czdd,
- Czhj,
- Xzrq,
- Jrry,
- Tpjydd,
- Tpjysd,
- Qywz,
- Clfcz,
- Clcz,
- Bdtj,
- Bdzl,
- Tjphcz,
- Tjphfcz,
- Lx,
- Hwhy,
- Zyhy,
- Wxhy,
- Ddhy,
- Ym,
- Jb,
- Jrjb,
- Cs,
- Sy,
- Dc,
- Jd,
- Jz,
- Glzd,
- Glsd,
- Fy,
- Qcyy,
- Frdrq,
- Fr,
- Hb,
- Rs,
- Js,
- Mj,
- Fs,
- Fb,
- },
- computed: {
- stepComponentMap() {
- if (!this.componentMap) {
- this.componentMap = {
- 'czdd': 'Czdd',
- 'czhj': 'Czhj',
- 'xzrq': 'Xzrq',
- 'jrry': 'Jrry',
- 'tpjydd': 'Tpjydd',
- 'tpjysd': 'Tpjysd',
- 'qywz': 'Qywz',
- 'clfcz': 'Clfcz',
- 'clcz': 'Clcz',
- 'bdtj': 'Bdtj',
- 'bdzl': 'Bdzl',
- 'tjphcz': 'Tjphcz',
- 'tjphfcz': 'Tjphfcz',
- 'lx': 'Lx',
- 'hwhy': 'Hwhy',
- 'zyhy': 'Zyhy',
- 'wxhy': 'Wxhy',
- 'ddhy': 'Ddhy',
- 'ym': 'Ym',
- 'jb': 'Jb',
- 'jrjb': 'Jrjb',
- 'sy': 'Sy',
- 'cs': 'Cs',
- 'dc': 'Dc',
- 'jd': 'Jd',
- 'jz': 'Jz',
- 'glzd': 'Glzd',
- 'glsd': 'Glsd',
- 'fy': 'Fy',
- 'qcyy': 'Qcyy',
- 'frdrq': 'Frdrq',
- 'fr': 'Fr',
- 'hb': 'Hb',
- 'rs': 'Rs',
- 'js': 'Js',
- 'mj': 'Mj',
- 'fs': 'Fs',
- 'fb': 'Fb',
- }
- }
- return this.componentMap
- }
- },
-
- created() {
- // // 初始化步骤数据
- // if (this.value && this.value.length > 0) {
- // this.steps = this.value.map((step) => ({
- // id: this.stepId++,
- // type: step.type || '',
- // formData: step.formData || {}
- // }))
- // } else {
- // // 默认添加一个步骤
- // this.addStep()
- // }
- },
- watch: {
- // steps: {
- // handler(newVal) {
- // this.$emit('input', newVal.map(step => ({
- // type: step.type,
- // formData: step.formData
- // })))
- // },
- // deep: true
- // },
- formData: {
- handler(newVal) {
- if (!newVal || newVal.length === 0) return
- this.steps = newVal;
- },
- deep: true,
- immediate: true
- }
- },
- methods: {
- isShowAddStep() {
- return this.templateFillType === 'preFill';
- },
- addStep() {
- try {
- this.steps.push({
- id: this.stepId++,
- type: '',
- formData: {}
- })
- this.$emit('step-added', this.steps.length)
- } catch (error) {
- console.error('添加步骤失败:', error)
- this.$message.error('添加步骤失败,请重试')
- }
- },
-
- removeStep(index) {
-
- if (this.steps.length > 1) {
- const removedStep = this.steps.splice(index, 1)[0]
- this.$emit('step-removed', { index, step: removedStep, remaining: this.steps.length })
- } else {
- this.$message.warning('至少需要保留一个步骤')
- }
- },
-
- onTypeChange(index) {
- // 切换步骤类型时重置表单数据,并确保数据更新
- const oldType = this.steps[index].type
- this.$set(this.steps[index], 'formData', {})
- // 可选:添加类型变化的回调
- this.$emit('step-type-changed', {
- index,
- newType: this.steps[index].type,
- oldType
- })
- },
-
- onFormUpdate(stepIndex, formData) {
- this.steps[stepIndex].formData = formData
- },
-
- getStepComponent(type) {
- // 使用计算属性中的映射,提高性能
- return this.stepComponentMap[type]
- },
-
- // 公共方法:获取所有步骤数据
- getFormData() {
- return new Promise(async (resolve, reject) => {
- // 检查是否有步骤数据
- if (this.steps.length === 0) {
- // this.$message.error(this.$t('template.common.addStepError'))
- reject({ errorType: "step" });
- return
- }
-
- try {
- const stepData = await Promise.all(
- this.steps.map(async (step, index) => {
- const stepComponentRef = this.$refs[`stepCompRef_${index}`];
- if (stepComponentRef && stepComponentRef.length > 0) {
- try {
- const stepFormData = await stepComponentRef[0].getFormData();
- return { type: step.type, formData: stepFormData }
- } catch (error) {
- // 如果某个步骤的getFormData方法失败,抛出错误
- throw error;
- }
- } else {
- // 如果没有找到组件引用,返回原始数据
- return { type: step.type, formData: step.formData }
- }
- })
- );
- resolve({ stepData });
- } catch (error) {
- reject(error);
- }
- })
- },
- getStepResource(){
- const sj = [];
- let yq = [];
- this.steps.map((step, index) => {
- const stepComponentRef = this.$refs[`stepCompRef_${index}`];
- if(stepComponentRef && stepComponentRef.length > 0){
- const {sjResource,yqResource} = this.$refs[`stepCompRef_${index}`][0]?.getSjResource();
- if(sjResource && sjResource.length > 0){
- sj.push(...sjResource);
- }
- if(yqResource && yqResource.length > 0){
- yq.push(...yqResource);
- }
- }
- })
- const resource = duplicateResource(sj, yq);
- return { sjResource: resource.sj, yqResource: resource.yq };
- },
-
- // 直接获取表单数据,不做校验
- getFilledFormData() {
- const stepData = this.steps.map((step, index) => {
- const stepComponentRef = this.$refs[`stepCompRef_${index}`];
- if(stepComponentRef && stepComponentRef.length > 0){
- const stepFormData = this.$refs[`stepCompRef_${index}`][0]?.getFilledFormData();
- return { type: step.type, formData: stepFormData }
- }else{
- return { type: step.type, formData: step.formData }
- }
- })
- return { stepData }
- },
-
- // 公共方法:设置步骤数据
- setStepData(data) {
- if (Array.isArray(data)) {
- this.steps = data.map(step => ({
- id: this.stepId++,
- type: step.type || '',
- formData: step.formData || {}
- }))
- }
- },
-
- // 公共方法:重置所有步骤
- resetSteps() {
- this.steps = [{
- id: this.stepId++,
- type: '',
- formData: {}
- }]
- this.$emit('steps-reset')
- },
-
- // 公共方法:获取指定步骤的数据
- getStepDataByIndex(index) {
- if (index >= 0 && index < this.steps.length) {
- return {
- type: this.steps[index].type,
- formData: this.steps[index].formData
- }
- }
- return null
- },
-
- // 公共方法:验证所有步骤
- async validateSteps() {
- const errors = []
- for (let index = 0; index < this.steps.length; index++) {
- const step = this.steps[index];
-
- if (!step.type) {
- errors.push(`步骤 ${index + 1}: 请选择步骤类型`)
- continue;
- }
-
- // 获取当前步骤的组件实例
- const stepComponentRef = this.$refs[`stepCompRef_${index}`];
- if (stepComponentRef && stepComponentRef.length > 0) {
- try {
- // 调用子组件的getFormData方法进行验证(不抛出错误,只验证)
- await stepComponentRef[0].validateAndMarkRed();
- } catch (error) {
- // validateAndMarkRed方法不应该抛出错误,但如果有的话捕获它
- console.error(`步骤 ${index + 1} 验证时出错:`, error);
- }
- }
- }
- return {
- isValid: errors.length === 0,
- errors
- }
- },
-
- // 公共方法:批量导入步骤数据
- importSteps(stepDataArray) {
- if (Array.isArray(stepDataArray)) {
- this.steps = stepDataArray.map((step, index) => ({
- id: this.stepId++,
- type: step.type || '',
- formData: step.formData || {}
- }))
- this.$emit('steps-imported', this.steps.length)
- }
- },
-
- // 公共方法:获取步骤统计信息
- getStepStatistics() {
- const stats = {
- total: this.steps.length,
- byType: {},
- filled: 0
- }
-
- this.steps.forEach(step => {
- // 统计各类型数量
- if (step.type) {
- stats.byType[step.type] = (stats.byType[step.type] || 0) + 1
- }
-
- // 统计已填写的步骤
- if (step.type && Object.keys(step.formData).length > 0) {
- stats.filled++
- }
- })
-
- return stats
- }
- },
-
- }
- </script>
-
- <style lang="scss" scoped>
- .step-container {
- box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
- margin-top: 24px;
- padding: 24px;
- border-radius: 5px 5px;
-
- .step-header {
- margin-bottom: 20px;
- padding: 15px;
- background: #f5f7fa;
- border-radius: 6px;
- }
- .flex1 {
- flex:1
- }
- .step-list {
- .step-list-item {
- margin-top: 10px;
- border-radius: 6px;
- overflow: hidden;
-
- .step-title {
- margin-right: 10px;
- margin-top: 6px;
- }
-
- .step-type-select {
- width: 200px;
- margin-right: 10px;
- max-width: 200px;
- }
-
- .delete-btn {
- color: #f56c6c;
-
- &:hover {
- color: #f78989;
- }
-
- &:disabled {
- color: #c0c4cc;
- }
- }
-
- .step-content {
- display: flex;
- align-items: flex-start;
- }
- }
- }
- }
- </style>
|