<template>
    <view class="ie-root">
        <view class="ie-body">
            <!-- 左侧：三级树形目录；独立于右侧项目列表滚动 -->
            <view class="ie-tree-wrap">
                <view class="ie-tree-search">
                    <input
                        class="ie-tree-search__input"
                        v-model="treeSearchKey"
                        placeholder="搜索目录"
                        confirm-type="search"
                    />
                    <text v-if="treeSearchKey" class="ie-tree-search__clear" @tap="clearTreeSearch">✕</text>
                </view>
                <scroll-view class="ie-tree" scroll-y>
                    <view class="ie-tree__empty" v-if="filteredTreeList.length === 0">
                        <text>无匹配目录</text>
                    </view>
                    <view class="ie-tree__group" v-for="(item, index) in filteredTreeList" :key="item.CBid">
                    <view
                        class="ie-tree__item ie-tree__item--l1"
                        :class="{ 'ie-tree__item--active': activeCBid === item.CBid && activeHBid === '' }"
                        @tap="tapL1(item)"
                    >
                        <view class="ie-tree__l1-row">
                            <text v-if="hasChildren(item)" class="ie-tree__arrow" :class="{ 'ie-tree__arrow--open': item._open }">›</text>
                            <text v-else class="ie-tree__arrow ie-tree__arrow--placeholder"></text>
                            <text class="ie-tree__l1-text">{{ item.descripts }}</text>
                            <text class="ie-tree__count" v-if="item.medCount > 0">{{ item.medCount }}</text>
                        </view>
                    </view>
                    <!-- 二级目录 -->
                    <view v-if="item._open && item.children && item.children.length">
                        <view
                            class="ie-tree__branch"
                            v-for="(child, cIndex) in item.children"
                            :key="child.HBid"
                        >
                            <view
                                class="ie-tree__item ie-tree__item--l2"
                            :class="{
                                'ie-tree__item--active': activeHBid === child.HBid,
                                'ie-tree__item--parent-active': activeL2HBid === child.HBid && activeHBid !== child.HBid
                            }"
                            @tap="tapL2(item, child)"
                            >
                                <view class="ie-tree__l2-row">
                                    <text v-if="hasChildren(child)" class="ie-tree__arrow ie-tree__arrow--l2" :class="{ 'ie-tree__arrow--open': child._open }">›</text>
                                    <text v-else class="ie-tree__arrow ie-tree__arrow--l2 ie-tree__arrow--placeholder"></text>
                                    <text class="ie-tree__l2-text">{{ child.descripts }}</text>
                                    <text class="ie-tree__count" v-if="child.medCount > 0">{{ child.medCount }}</text>
                                </view>
                            </view>
                            <!-- 三级目录 -->
                            <view v-if="child._open && child.children && child.children.length">
                                <view
                                    class="ie-tree__item ie-tree__item--l3"
                                    :class="{ 'ie-tree__item--active': activeHBid === grandchild.HBid }"
                                    v-for="grandchild in child.children"
                                    :key="grandchild.HBid"
                                    @tap="tapL3(item, child, grandchild)"
                                >
                                    <text class="ie-tree__l3-text">{{ grandchild.descripts }}</text>
                                    <text class="ie-tree__count" v-if="grandchild.medCount > 0">{{ grandchild.medCount }}</text>
                                </view>
                            </view>
                        </view>
                    </view>
                </view>
                </scroll-view>
            </view>

            <!-- 右侧：固定工具栏 + 独立滚动的项目列表 -->
            <view class="ie-list-panel">
                <view class="ie-search">
                    <view class="ie-search__box">
                        <input
                            class="ie-search__input"
                            v-model="searchCode"
                            placeholder="请输入搜索关键词"
                            confirm-type="search"
                            @confirm="onSearch"
                        />
                        <text class="ie-search__btn" @tap="onSearch">搜索</text>
                    </view>
                </view>
                <view class="ie-list__header" v-if="medicalList.length > 0 || searchCode">
                    <text class="ie-list__selected" @tap="showSelectedList">已选 {{ selectedCount }} 项</text>
                    <view class="ie-list__select-all" @tap="toggleSelectAll" v-if="medicalList.length > 0 && !hasOTypeItem">
                        <view class="ie-list__checkbox" :class="{ 'ie-list__checkbox--checked': isAllSelected }">
                            <text v-if="isAllSelected" class="ie-list__check-icon">✓</text>
                        </view>
                        <text class="ie-list__select-all-text">{{ isAllSelected ? '取消' : '全选' }}</text>
                    </view>
                </view>
                <scroll-view class="ie-list" scroll-y>
                    <view class="ie-list__empty" v-if="medicalList.length === 0 && !loading">
                        <text>暂无项目</text>
                    </view>
                    <view
                        class="ie-list__item"
                        v-for="(item, index) in medicalList"
                        :key="item.medID"
                        @tap="item.orderTypeCode === 'O' ? toggleOItem(item) : toggleItem(item)"
                    >
                        <view class="ie-list__item-info">
                            <text class="ie-list__item-name">{{ item.medDesc }}</text>
                            <text class="ie-list__item-price">¥{{ item.medPrice }}</text>
                        </view>
                        <!-- O 类型：加减步进器 -->
                        <view v-if="item.orderTypeCode === 'O'" class="ie-stepper" @tap.stop>
                            <text
                                v-if="getOQty(item.medID) > 0"
                                class="ie-stepper__btn"
                                :class="{ 'ie-stepper__btn--disabled': getOQty(item.medID) <= 1 }"
                                @tap.stop="decreaseO(item)"
                            >−</text>
                            <text v-if="getOQty(item.medID) > 0" class="ie-stepper__num">{{ getOQty(item.medID) }}</text>
                            <text class="ie-stepper__btn" @tap.stop="increaseO(item)">+</text>
                        </view>
                        <!-- 非 O 类型：复选框 -->
                        <view v-else class="ie-list__checkbox" :class="{ 'ie-list__checkbox--checked': isSelected(item.medID) }">
                            <text v-if="isSelected(item.medID)" class="ie-list__check-icon">✓</text>
                        </view>
                    </view>
                </scroll-view>
            </view>
        </view>

        <!-- 底部保存按钮 -->
        <view class="ie-footer">
            <button :disabled="saving" class="ie-footer__btn" :class="{ 'ie-footer__btn--disabled': selectedCount === 0 || saving }" @tap="onSave">
                {{ saving ? '保存中...' : '保存' + (selectedCount > 0 ? '（已选 ' + selectedCount + ' 项）' : '') }}
            </button>
        </view>

        <!-- 已选项目弹层 -->
        <view class="ie-popup-mask" v-if="showSelectedPopup" @tap="hideSelectedList"></view>
        <view class="ie-popup" :class="{ 'ie-popup--show': showSelectedPopup }">
            <view class="ie-popup__header">
                <text class="ie-popup__title">已选项目（{{ selectedCount }}）</text>
                <text class="ie-popup__close" @tap="hideSelectedList">✕</text>
            </view>
            <scroll-view class="ie-popup__body" scroll-y>
                <view class="ie-popup__empty" v-if="selectedCount === 0">
                    <text>暂无已选项目</text>
                </view>
                <view class="ie-popup__item" v-for="(item, index) in selectedList" :key="item.medID">
                    <view class="ie-popup__item-info">
                        <text class="ie-popup__item-name">{{ item.medDesc }}</text>
                        <view class="ie-popup__item-meta">
                            <text class="ie-popup__item-price">¥{{ item.medPrice }}</text>
                            <text v-if="item.mainCode === 'O'" class="ie-popup__item-qty-label">×{{ item.qty || 1 }}</text>
                        </view>
                    </view>
                    <!-- O 类型：弹窗内步进器 -->
                    <view v-if="item.mainCode === 'O'" class="ie-stepper ie-stepper--popup" @tap.stop>
                        <text
                            v-if="(item.qty || 0) > 0"
                            class="ie-stepper__btn"
                            :class="{ 'ie-stepper__btn--disabled': (item.qty || 1) <= 1 }"
                            @tap.stop="decreaseO(item)"
                        >−</text>
                        <text v-if="(item.qty || 0) > 0" class="ie-stepper__num">{{ item.qty || 1 }}</text>
                        <text class="ie-stepper__btn" @tap.stop="increaseO(item)">+</text>
                    </view>
                    <text class="ie-popup__item-remove" @tap="removeSelected(item)">取消</text>
                </view>
            </scroll-view>
        </view>

        <van-toast id="van-toast" />
        <van-dialog id="van-dialog" />
    </view>
</template>

<script>
import Cache from '../../../../../../../../utils/cache';
import { $http } from '../../../../../../../../config/https';
import Toast from '../../../../../../../../utils/toast';
import Dialog from '../../../../../../../../utils/dialog';

export default {
    components: {},
    data() {
        return {
            treeList: [],
            medicalList: [],
            activeCBid: '',
            activeHBid: '',
            activeL2HBid: '',
            // 当前选中一级目录的 mainCode：L=检验，E=检查
            activeMainCode: '',
            currentTitle: '',
            selectedMap: {},
            loading: false,
            saving: false,
            showSelectedPopup: false,
            searchCode: '',
            treeSearchKey: '',
        };
    },
    options: {
        addGlobalClass: true
    },
    props: {
        active: {
            type: Number,
            default: 0
        },

        diagData: {
            type: Object,
            //诊断对象（含 id / diagCode / diagDesc）
            default: () => ({}) //默认值
        }
    },
    watch: {
        active: {
            handler(val) {
                this.getTree();
            },
            immediate: true
        }
    },
    computed: {
        selectedCount() {
            let count = 0;
            const map = this.selectedMap;
            Object.keys(map).forEach((id) => {
                const item = map[id];
                if (item.mainCode === 'O') {
                    count += (item.qty || 0);
                } else {
                    count += 1;
                }
            });
            return count;
        },
        selectedList() {
            // O 类型 qty=0 的不在弹窗中展示
            return Object.values(this.selectedMap).filter((item) => {
                if (item.mainCode === 'O') return (item.qty || 0) > 0;
                return true;
            });
        },
        // 当前右侧列表中是否含有 O 类型的项目（O 类型不适用全选逻辑）
        hasOTypeItem() {
            return this.medicalList.some((item) => item.orderTypeCode === 'O');
        },
        // 当前右侧列表是否全部已选（仅判断当前 medicalList，不含其它目录已选项）
        isAllSelected() {
            if (this.medicalList.length === 0) {
                return false;
            }
            return this.medicalList.every((item) => !!this.selectedMap[item.medID]);
        },
        // 左侧树搜索：按 descripts 关键词过滤，命中节点的所有祖先路径全部保留并展开
        filteredTreeList() {
            const keyword = (this.treeSearchKey || '').trim().toLowerCase();
            if (!keyword) {
                // 无搜索词时恢复原始树（保持各节点当前的展开状态）
                return this.treeList;
            }
            const match = (text) => {
                return !!(text && String(text).toLowerCase().indexOf(keyword) > -1);
            };
            const filterNode = (node) => {
                const selfMatch = match(node.descripts);
                let children = (node.children || []).map((c) => filterNode(c)).filter((c) => !!c);
                if (selfMatch) {
                    // 自身命中：保留全部子节点并展开
                    return { ...node, _open: true, children: node.children || [] };
                }
                if (children.length > 0) {
                    // 子节点命中：保留命中子树并展开自身
                    return { ...node, _open: true, children };
                }
                return null;
            };
            return this.treeList
                .map((node) => filterNode(node))
                .filter((node) => !!node);
        }
    },
    mounted() {
        this.attached();
        this.$nextTick(() => this.ready());
    },
    destroyed() {},
    methods: {
        // ready() {
        //     this.getTree();
        // },
        attached() {},

        // 计算属性兼容：selectedMap 在模板中以 .size 访问可能不生效，用方法兜底
        isSelected(medID) {
            return !!this.selectedMap[medID];
        },

        hasChildren(node) {
            return !!(node && node.children && node.children.length);
        },

        // 清空左侧树搜索
        clearTreeSearch() {
            this.treeSearchKey = '';
        },

        normalizeTree(list) {
            return (list || []).map((item) => ({
                ...item,
                _open: false,
                children: this.normalizeTree(item.children)
            }));
        },

        // 展示已选项目弹层
        showSelectedList() {
            this.setData({ showSelectedPopup: true });
        },

        // 隐藏已选项目弹层
        hideSelectedList() {
            this.setData({ showSelectedPopup: false });
        },

        // 从弹层中移除已选项目（O 类型 qty 置 0）
        removeSelected(item) {
            const map = { ...this.selectedMap };
            if (map[item.medID]) {
                if (item.mainCode === 'O') {
                    map[item.medID] = { ...map[item.medID], qty: 0 };
                } else {
                    delete map[item.medID];
                }
            }
            this.setData({ selectedMap: map });
        },

        // 获取检验检查目录树
        getTree() {
            const userData = Cache.get('userData');
            $http.post('urlDeault', this, {
                code: '03010004',
                data: {
                    params: [
                        {
                            CBid: this.active == 3 ? '4' : '', // 仅获取治疗的数据
                            hospID: userData.hospID
                        }
                    ]
                },
                success: (res) => {
                    if (res.errorCode === '0') {
                        const list = this.normalizeTree(res.data);
                        this.setData({ treeList: list }, () => {
                            // 默认展开第一个有子项的一级目录并加载项目
                            if (list.length > 0) {
                                const first = list[0];
                                first._open = true;
                                this.setData({
                                    treeList: list,
                                    activeCBid: first.CBid,
                                    activeHBid: '',
                                    activeL2HBid: '',
                                    activeMainCode: first.mainCode || '',
                                    currentTitle: first.descripts
                                });
                                this.getMedicalList(first.CBid, '');
                            }
                        });
                    }
                }
            });
        },

        // 获取目录下项目列表
        getMedicalList(CBid, appTypeID) {
            const userData = Cache.get('userData');
            const patientData = Cache.get('patientData');
            this.setData({ loading: true });
            const params = {
                hospID: userData.hospID,
                locID: userData.locID,
                admID: patientData.admID
            };
            // 有 appTypeID（二级或三级）时用 appTypeID，否则用 CBid（一级）
            if (appTypeID) {
                params.appTypeID = appTypeID;
            } else {
                params.CBid = CBid;
            }
            // 增加搜索编码入参
            if (this.searchCode) {
                params.searchCode = this.searchCode;
            }
            $http.post('urlDeault', this, {
                code: '03050098',
                data: {
                    params: [params]
                },
                success: (res) => {
                    if (res.errorCode === '0') {
                        this.setData({
                            medicalList: res.result || [],
                            loading: false
                        });
                    } else {
                        this.setData({ loading: false, medicalList: [] });
                    }
                },
                fail: () => {
                    this.setData({ loading: false, medicalList: [] });
                }
            });
        },

        // 点击一级目录：展开/折叠 + 加载该类全部项目
        tapL1(item) {
            const list = this.treeList.map((n) => {
                if (n.CBid === item.CBid) {
                    return { ...n, _open: this.hasChildren(n) ? !n._open : false };
                }
                return n;
            });
            this.setData({
                treeList: list,
                activeCBid: item.CBid,
                activeHBid: '',
                activeL2HBid: '',
                activeMainCode: item.mainCode || '',
                currentTitle: item.descripts
            });
            this.getMedicalList(item.CBid, '');
        },

        // 点击二级目录：展开/折叠三级目录，同时加载该二级目录项目
        tapL2(parent, child) {
            const list = this.treeList.map((item) => {
                if (item.CBid !== parent.CBid) {
                    return item;
                }
                return {
                    ...item,
                    children: item.children.map((node) =>
                        node.HBid === child.HBid ? { ...node, _open: this.hasChildren(node) ? !node._open : false } : node
                    )
                };
            });
            this.setData({
                treeList: list,
                activeCBid: parent.CBid,
                activeHBid: child.HBid,
                activeL2HBid: child.HBid,
                activeMainCode: parent.mainCode || '',
                currentTitle: parent.descripts + ' / ' + child.descripts
            });
            this.getMedicalList('', child.HBid);
        },

        // 点击三级目录：按三级目录加载项目
        tapL3(parent, child, grandchild) {
            this.setData({
                activeCBid: parent.CBid,
                activeHBid: grandchild.HBid,
                activeL2HBid: child.HBid,
                activeMainCode: parent.mainCode || '',
                currentTitle: parent.descripts + ' / ' + child.descripts + ' / ' + grandchild.descripts
            });
            this.getMedicalList('', grandchild.HBid);
        },

        // 搜索项目
        onSearch() {
            // 优先按当前选中的二级目录搜索，否则按一级目录搜索
            if (this.activeHBid) {
                this.getMedicalList('', this.activeHBid);
            } else if (this.activeCBid) {
                this.getMedicalList(this.activeCBid, '');
            }
        },

        // 切换项目勾选（L/E 类型）
        toggleItem(item) {
            const map = { ...this.selectedMap };
            if (map[item.medID]) {
                delete map[item.medID];
            } else {
                map[item.medID] = {
                    medID: item.medID,
                    medDesc: item.medDesc,
                    medPrice: item.medPrice,
                    CBid: this.activeCBid,
                    HBid: this.activeHBid,
                    // 03050098 接口直接返回 orderTypeCode：L=检验，E=检查；用于保存时区分 bodyPart/tabIndex
                    mainCode: item.orderTypeCode || '',
                    // 03050098 接口返参 appOrderID，保存时传入 03050001 的 orders 中
                    appOrderID: item.appOrderID || '',
                    qty: 1
                };
            }
            this.setData({ selectedMap: map });
        },

        // O 类型项目：点击行切换选中/取消（qty=0 时变为 qty=1 选中）
        toggleOItem(item) {
            const map = { ...this.selectedMap };
            const existed = map[item.medID];
            if (existed && existed.qty > 0) {
                // 已选中且有数量 → 取消（qty 置 0）
                map[item.medID] = { ...existed, qty: 0 };
            } else {
                // 未选中或 qty=0 → 选中（qty=1）
                map[item.medID] = {
                    medID: item.medID,
                    medDesc: item.medDesc,
                    medPrice: item.medPrice,
                    CBid: this.activeCBid,
                    HBid: this.activeHBid,
                    mainCode: item.orderTypeCode || '',
                    appOrderID: item.appOrderID || '',
                    qty: 1
                };
            }
            this.setData({ selectedMap: map });
        },

        // O 类型项目：获取当前数量（0 表示未选或已减到 0）
        getOQty(medID) {
            const item = this.selectedMap[medID];
            return item ? (item.qty || 0) : 0;
        },

        // O 类型项目：增加数量
        increaseO(item) {
            const map = { ...this.selectedMap };
            if (map[item.medID]) {
                map[item.medID] = { ...map[item.medID], qty: (map[item.medID].qty || 0) + 1 };
            } else {
                map[item.medID] = {
                    medID: item.medID,
                    medDesc: item.medDesc,
                    medPrice: item.medPrice,
                    CBid: this.activeCBid,
                    HBid: this.activeHBid,
                    mainCode: item.orderTypeCode || '',
                    appOrderID: item.appOrderID || '',
                    qty: 1
                };
            }
            this.setData({ selectedMap: map });
        },

        // O 类型项目：减少数量（qty=0 时保留记录，仅显示 + 号）
        decreaseO(item) {
            const map = { ...this.selectedMap };
            if (map[item.medID]) {
                const newQty = (map[item.medID].qty || 1) - 1;
                map[item.medID] = { ...map[item.medID], qty: newQty };
            }
            this.setData({ selectedMap: map });
        },

        // 全选 / 取消全选（针对当前右侧列表 medicalList，仅 L/E 类型可用）
        toggleSelectAll() {
            const map = { ...this.selectedMap };
            if (this.isAllSelected) {
                // 当前列表已全部选中 → 取消当前列表的全选
                this.medicalList.forEach((item) => {
                    if (map[item.medID]) {
                        delete map[item.medID];
                    }
                });
            } else {
                // 否则把当前列表全部加入已选
                this.medicalList.forEach((item) => {
                    if (!map[item.medID]) {
                        map[item.medID] = {
                            medID: item.medID,
                            medDesc: item.medDesc,
                            medPrice: item.medPrice,
                            CBid: this.activeCBid,
                            HBid: this.activeHBid,
                            // 03050098 接口直接返回 orderTypeCode：L=检验，E=检查
                            mainCode: item.orderTypeCode || '',
                            // 03050098 接口返参 appOrderID，保存时传入 03050001 的 orders 中
                            appOrderID: item.appOrderID || '',
                            qty: 1
                        };
                    }
                });
            }
            this.setData({ selectedMap: map });
        },

        // 格式化日期时间
        formatDateTime() {
            const now = new Date();
            const pad = (n) => (n < 10 ? '0' + n : '' + n);
            const date = now.getFullYear() + '-' + pad(now.getMonth() + 1) + '-' + pad(now.getDate());
            const time = pad(now.getHours()) + ':' + pad(now.getMinutes()) + ':' + pad(now.getSeconds());
            return { date, time };
        },

        // 保存：直接调用 03050001 提交
        onSave() {
            const selected = Object.values(this.selectedMap).filter((item) => {
                // O 类型 qty=0 的不参与保存
                if (item.mainCode === 'O') return (item.qty || 0) > 0;
                return true;
            });
            if (selected.length === 0) {
                Toast({ type: 'fail', message: '请选择项目', context: this });
                return;
            }
            this.setData({ saving: true }, ()=>{
                // 先查询所有已选项目的默认数据（数量单位、执行科室等），再提交保存
                this.fetchDefaultDataAndSave(selected);
            }); 
        },

        // 批量查询已选项目的默认数据后提交保存
        fetchDefaultDataAndSave(selected) {
            const patientData = Cache.get('patientData');
            const userData = Cache.get('userData');
            const { admID } = patientData;
            const { userID, locID, hospID } = userData;
            const { date, time } = this.formatDateTime();

            // 构造 03050020 的 orders 入参
            const queryOrders = selected.map((item) => ({
                medID: item.medID,
                ordSetID: ''
            }));

            $http.post('urlDeault', this, {
                code: '03050020',
                data: {
                    params: [
                        {
                            admID: admID || '',
                            orders: queryOrders
                        }
                    ]
                },
                success: (res) => {
                    if (res.errorCode === '0') {
                        const dataList = res.data || [];
                        // medID -> defaultData 映射，便于按选中顺序构造 orders
                        const defaultMap = {};
                        dataList.forEach((d) => {
                            if (d && d.defaultData && d.defaultData.medID) {
                                defaultMap[d.defaultData.medID] = d.defaultData;
                            }
                        });

                        const orders = selected.map((item, index) => {
                            const def = defaultMap[item.medID] || {};
                            // 仅检查(mainCode='E')需要 bodyPart 三层结构：
                            // orders.ordbodyPart=[null] -> appMessage.bodyPart[].bodyPart[].bodyPart=[]。
                            const isExamination = (item.mainCode || '').toUpperCase() === 'E';
                            const order = {
                                ordMedItemDesc: item.medDesc,
                                medID: item.medID,
                                ordPrice: def.ordPrice || 0,
                                ordQty: (item.mainCode === 'O') ? (item.qty || 1) : (def.ordQty || 1),
                                ordDose: def.ordDose || 1,
                                ordDate: date,
                                ordTime: time,
                                ordStartDate: date,
                                ordStartTime: time,
                                ordSpecID: def.ordSpecID || '',
                                ordEMFlag: def.ordEMFlag || '',
                                ordPriorityID: def.ordPriorityID || '10',
                                ordAdmReasonID: def.ordAdmReasonID || '1',
                                // 保持原有规则：每个选中项目按其顺序分配 tabIndex。
                                tabIndex: index + 1,
                                ordRecLocID: def.ordRecLocID || locID || '',
                                ordQtyUomID: def.ordQtyUomID || '',
                                ordSeqNo: index,
                                // 03050098 接口返参 appOrderID，传入 03050001 的 orders 中
                                appOrderID: item.appOrderID || '',
                                // 内部字段：保存时区分检验/检查，提交给后端前会被剔除
                                _mainCode: item.mainCode || '',
                                extvalue: [
                                    {
                                        code: 'Diag',
                                        value: (this.diagData && this.diagData.id) || '',
                                        refDescripts: (this.diagData && this.diagData.diagCode) || ''
                                    },
                                    { code: 'RegDate', value: '', refDescripts: '预约执行日期' }
                                ]
                            };

                            if (isExamination) {
                                // 后端允许最内层 bodyPart 为空，但该字段不能缺失。
                                order.ordbodyPart = [null];
                            }
                            return order;
                        });

                        this.submitOrders(orders, admID, locID, userID, hospID);
                    } else {
                        this.setData({ saving: false });
                        Dialog.alert({
                            title: '提示',
                            message: res.errorMessage || '获取医嘱默认数据失败',
                            context: this
                        });
                    }
                },
                fail: (err) => {
                    this.setData({ saving: false });
                    Dialog.alert({
                        title: '提示',
                        message: (err && err.errorMessage) || '获取医嘱默认数据失败',
                        context: this
                    });
                }
            });
        },

        // 调用 03050001 提交 orders
        submitOrders(orders, admID, locID, userID, hospID) {
            // 依据每个 order 所属类型(_mainCode)区分检验(L)与检查(E)：
            // - 检查(E)：按 tabIndex 分组生成 appMessage.bodyPart 数组，每项 { bodyPart:[...], tabIndex }
            //   内层 bodyPart 数组由该 tab 下各 order 的 ordbodyPart 元素映射而来，
            //   null(未选部位) 映射为空数组 []，非空则取部位本身
            // - 检验(L)：不传 bodyPart，不参与分组
            const bodyPartGroup = {};
            orders.forEach((order) => {
                // L=检验，E=检查
                const isInspection = (order._mainCode || '').toUpperCase() === 'E';
                if (!isInspection) {
                    return;
                }
                const tabIndex = order.tabIndex;
                if (!bodyPartGroup[tabIndex]) {
                    bodyPartGroup[tabIndex] = [];
                }
                (order.ordbodyPart || []).forEach((part) => {
                    bodyPartGroup[tabIndex].push({ bodyPart: part == null ? [] : part });
                });
            });
            const bodyPartArr = Object.keys(bodyPartGroup).map((tabIndex) => ({
                bodyPart: bodyPartGroup[tabIndex],
                tabIndex: Number(tabIndex)
            }));

            // 剔除内部字段 _mainCode，避免提交给后端
            const cleanOrders = orders.map((order) => {
                const { _mainCode, ...rest } = order;
                return rest;
            });

            const appMessage = {
                appPurpose: '',
                HPIllness: '',
                sign: '',
                chiefComplaint: '',
                // 检验项目不参与 bodyPart 分组；全是检验时传空数组。
                bodyPart: bodyPartArr.length > 0 ? bodyPartArr : [],
            };
            $http.post('urlDeault', this, {
                code: '03050001',
                data: {
                    params: [
                        {
                            admID: admID || '',
                            locID: locID || '',
                            docID: userID || '',
                            userID: userID || '',
                            hospID: hospID || '',
                            medType: 'WM',
                            orders: cleanOrders,
                            appMessage: appMessage
                        }
                    ]
                },
                success: (res) => {
                    if (res.errorCode == 0) {
                        // 设置标记，供 prescription.vue 的 handlePageShow 检测并刷新已确认数据
                        try {
                            Cache.set('inspectionExamineSaved', true);
                        } catch (e) {}
                        Toast({ type: 'success', message: '保存成功', context: this });
                        setTimeout(() => {
                            this.setData({ saving: false });
                            uni.navigateBack({ delta: 1 });
                        }, 800);
                    } else {
                        this.setData({ saving: false });
                        Dialog.alert({
                            title: '提示',
                            message: res.errorMessage || '保存失败',
                            context: this
                        });
                    }
                },
                fail: (res) => {
                    this.setData({ saving: false });
                    Dialog.alert({
                        title: '提示',
                        message: (res && res.errorMessage) || '保存失败',
                        context: this
                    });
                }
            });
        }
    },
    created() {}
};
</script>

<style>
.ie-root {
    --ie-footer-height: 116rpx;
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
    position: relative;
    overflow: hidden;
    width: 100%;
    height: 100%;
}

.ie-body {
    flex: 1;
    min-height: 0;
    display: flex;
    align-items: stretch;
    padding-bottom: calc(var(--ie-footer-height) + env(safe-area-inset-bottom));
    box-sizing: border-box;
    overflow: hidden;
}

/* 左侧目录树 */
.ie-tree-wrap {
    width: 39%;
    flex-shrink: 0;
    height: 100%;
    min-height: 0;
    display: flex;
    flex-direction: column;
    background: #fafbfc;
    border-right: 2rpx solid #f0f2f5;
    overflow: hidden;
}

.ie-tree-search {
    flex-shrink: 0;
    position: relative;
    padding: 16rpx 20rpx;
    background: #fff;
    border-bottom: 1rpx solid #f0f2f5;
    z-index: 2;
}

.ie-tree-search__input {
    width: 100%;
    height: 60rpx;
    background: #f4f7fb;
    border-radius: 999rpx;
    padding: 0 56rpx 0 24rpx;
    font-size: 24rpx;
    color: #1f2937;
    box-sizing: border-box;
}

.ie-tree-search__clear {
    position: absolute;
    right: 32rpx;
    top: 50%;
    transform: translateY(-50%);
    width: 32rpx;
    height: 32rpx;
    line-height: 32rpx;
    text-align: center;
    font-size: 24rpx;
    color: #9ca3af;
}

.ie-tree {
    flex: 1;
    min-height: 0;
    height: 100%;
    background: #fafbfc;
    overscroll-behavior: contain;
}

.ie-tree__empty {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 80rpx 0;
    color: #9ca3af;
    font-size: 26rpx;
}

.ie-tree__item {
    padding: 22rpx 16rpx;
    border-bottom: 1rpx solid #f0f2f5;
    position: relative;
}

.ie-tree__item--l1 {
    background: #fff;
}

.ie-tree__item--l2 {
    padding: 18rpx 16rpx 18rpx 40rpx;
    background: #fafbfc;
}

.ie-tree__item--l3 {
    display: flex;
    align-items: center;
    padding: 16rpx 16rpx 16rpx 76rpx;
    background: #fdfefe;
}

.ie-tree__item--active {
    color: #1890ff;
    background: #eef6ff !important;
}

.ie-tree__item--active::before {
    content: '';
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    width: 6rpx;
    background: #1890ff;
}

.ie-tree__item--parent-active {
    color: #1890ff;
    background: #f5faff !important;
}

.ie-tree__l1-row {
    display: flex;
    align-items: center;
}

.ie-tree__arrow {
    display: inline-block;
    width: 28rpx;
    font-size: 32rpx;
    color: #9ca3af;
    transition: transform 0.2s;
    transform: rotate(0deg);
    line-height: 1;
}

.ie-tree__arrow--open {
    transform: rotate(90deg);
}

.ie-tree__arrow--l2 {
    width: 24rpx;
    font-size: 28rpx;
}

.ie-tree__arrow--placeholder {
    visibility: hidden;
}

.ie-tree__l2-row {
    display: flex;
    align-items: center;
}

.ie-tree__l1-text {
    flex: 1;
    font-size: 28rpx;
    font-weight: 500;
    color: #1f2937;
}

.ie-tree__l2-text {
    flex: 1;
    min-width: 0;
    font-size: 26rpx;
    color: #4b5563;
    line-height: 1.4;
}

.ie-tree__l3-text {
    flex: 1;
    min-width: 0;
    font-size: 24rpx;
    color: #6b7280;
    line-height: 1.4;
}

.ie-tree__count {
    font-size: 22rpx;
    color: #9ca3af;
    background: #f0f2f5;
    border-radius: 20rpx;
    padding: 2rpx 12rpx;
    min-width: 32rpx;
    text-align: center;
}

.ie-tree__item--active .ie-tree__l1-text,
.ie-tree__item--active .ie-tree__l2-text,
.ie-tree__item--active .ie-tree__l3-text,
.ie-tree__item--parent-active .ie-tree__l2-text {
    color: #1890ff;
}

.ie-tree__item--active .ie-tree__count {
    color: #1890ff;
    background: #d6ebff;
}

/* 右侧固定工具栏 */
.ie-list-panel {
    flex: 1;
    min-width: 0;
    min-height: 0;
    height: 100%;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    background: #fff;
}

.ie-search {
    flex-shrink: 0;
    padding: 16rpx 24rpx;
    background: #fff;
    border-bottom: 1rpx solid #f0f2f5;
    z-index: 3;
}

.ie-search__box {
    display: flex;
    align-items: center;
    gap: 16rpx;
}

.ie-search__input {
    flex: 1;
    height: 64rpx;
    background: #f4f7fb;
    border-radius: 999rpx;
    padding: 0 24rpx;
    font-size: 26rpx;
    color: #1f2937;
}

.ie-search__btn {
    flex-shrink: 0;
    font-size: 26rpx;
    color: #1890ff;
    padding: 8rpx 16rpx;
}

/* 右侧项目列表 */
.ie-list {
    flex: 1;
    min-width: 0;
    min-height: 0;
    background: #fff;
    overscroll-behavior: contain;
}

.ie-list__header {
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 18rpx 24rpx;
    border-bottom: 1rpx solid #f0f2f5;
    background: #fff;
    z-index: 2;
}

.ie-list__title {
    font-size: 26rpx;
    font-weight: 500;
    color: #1f2937;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.ie-list__selected {
    font-size: 24rpx;
    color: #1890ff;
    flex-shrink: 0;
    margin-left: 16rpx;
}

.ie-list__select-all {
    display: flex;
    align-items: center;
    flex-shrink: 0;
}

.ie-list__select-all-text {
    font-size: 24rpx;
    color: #1890ff;
    margin-left: 10rpx;
}

.ie-list__empty {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 120rpx 0;
    color: #9ca3af;
    font-size: 26rpx;
}

.ie-list__item {
    display: flex;
    align-items: center;
    padding: 24rpx;
    border-bottom: 1rpx solid #f5f6f8;
}

.ie-list__item:active {
    background: #f9fafb;
}

.ie-list__item-info {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 6rpx;
}

.ie-list__item-name {
    font-size: 28rpx;
    color: #1f2937;
    line-height: 1.5;
}

.ie-list__item-price {
    font-size: 24rpx;
    color: #ef4444;
}

.ie-list__checkbox {
    flex-shrink: 0;
    width: 40rpx;
    height: 40rpx;
    border: 2rpx solid #d1d5db;
    border-radius: 8rpx;
    display: flex;
    align-items: center;
    justify-content: center;
    margin-left: 20rpx;
    background: #fff;
}

.ie-list__checkbox--checked {
    background: #1890ff;
    border-color: #1890ff;
}

/* O 类型步进器 */
.ie-stepper {
    flex-shrink: 0;
    display: flex;
    align-items: center;
    gap: 4rpx;
    margin-left: 12rpx;
}

.ie-stepper__btn {
    width: 44rpx;
    height: 44rpx;
    border-radius: 50%;
    background: #f0f2f5;
    color: #374151;
    font-size: 32rpx;
    font-weight: 600;
    display: flex;
    align-items: center;
    justify-content: center;
    line-height: 1;
    transition: all 0.15s;
}

.ie-stepper__btn:active {
    background: #e5e7eb;
    transform: scale(0.92);
}

.ie-stepper__btn--disabled {
    color: #d1d5db;
    background: #f8f9fa;
}

.ie-stepper__btn--disabled:active {
    transform: none;
    background: #f8f9fa;
}

.ie-stepper__num {
    min-width: 48rpx;
    text-align: center;
    font-size: 26rpx;
    font-weight: 600;
    color: #1f2937;
}

/* 弹窗中的步进器 */
.ie-stepper--popup {
    margin-left: auto;
    margin-right: 16rpx;
}

.ie-stepper--popup .ie-stepper__btn {
    width: 40rpx;
    height: 40rpx;
    font-size: 28rpx;
}

.ie-stepper--popup .ie-stepper__num {
    min-width: 40rpx;
    font-size: 24rpx;
}

.ie-list__check-icon {
    color: #fff;
    font-size: 26rpx;
    font-weight: bold;
    line-height: 1;
}

/* 底部保存按钮 */
.ie-footer {
    /*
     * H5 的 100vh 在部分 WebView 中会大于实际可视区，不能只依赖组件底部定位。
     * 固定到可视区底部，避免保存按钮需要随页面下滑才能出现。
     */
    position: fixed;
    right: 36rpx;
    bottom: 0;
    left: 36rpx;
    z-index: 10;
    padding: 16rpx 24rpx;
    padding-bottom: calc(16rpx + env(safe-area-inset-bottom));
    background: #fff;
    border-top: 1rpx solid #f0f2f5;
}

.ie-footer__btn {
    width: 100%;
    height: 84rpx;
    line-height: 84rpx;
    background: #1890ff;
    color: #fff;
    font-size: 30rpx;
    font-weight: 500;
    text-align: center;
    border-radius: 999rpx;
    padding: 0;
    margin: 0;
    border: 0;
}

.ie-footer__btn::after {
    border: initial;
}

.ie-footer__btn--disabled {
    background: #91cfff;
    color: #fff;
}

/* 已选项目弹层 */
.ie-popup-mask {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: rgba(0, 0, 0, 0.45);
    z-index: 100;
}

.ie-popup {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    max-height: 70vh;
    background: #fff;
    border-radius: 24rpx 24rpx 0 0;
    z-index: 101;
    display: flex;
    flex-direction: column;
    transform: translateY(100%);
    transition: transform 0.25s ease;
}

.ie-popup--show {
    transform: translateY(0);
}

.ie-popup__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 28rpx 32rpx 20rpx;
    border-bottom: 1rpx solid #f0f2f5;
    flex-shrink: 0;
}

.ie-popup__title {
    font-size: 30rpx;
    font-weight: 600;
    color: #1f2937;
}

.ie-popup__close {
    font-size: 32rpx;
    color: #9ca3af;
    padding: 8rpx 16rpx;
}

.ie-popup__body {
    flex: 1;
    min-height: 0;
    max-height: 55vh;
}

.ie-popup__empty {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 100rpx 0;
    color: #9ca3af;
    font-size: 26rpx;
}

.ie-popup__item {
    display: flex;
    align-items: center;
    padding: 24rpx 32rpx;
    border-bottom: 1rpx solid #f5f6f8;
}

.ie-popup__item-info {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 6rpx;
}

.ie-popup__item-name {
    font-size: 28rpx;
    color: #1f2937;
    line-height: 1.5;
}

.ie-popup__item-price {
    font-size: 24rpx;
    color: #ef4444;
}

.ie-popup__item-meta {
    display: flex;
    align-items: center;
    gap: 12rpx;
}

.ie-popup__item-qty-label {
    font-size: 24rpx;
    color: #6b7280;
    font-weight: 500;
}

.ie-popup__item-remove {
    flex-shrink: 0;
    font-size: 24rpx;
    color: #ef4444;
    padding: 8rpx 20rpx;
    border: 1rpx solid #ef4444;
    border-radius: 999rpx;
    margin-left: 20rpx;
}
</style>
