<template>
    <view class="search-page">
        <!-- pages/components/searchSelect/searchSelect.wxml -->
        <view class="search-header" :style="'height:' + navHeight + 'rpx;padding-top:' + statusHeight + 'rpx'">
            <view class="search-header__back" @tap="goBack">
                <text class="search-header__back-icon">‹</text>
            </view>
            <view class="search-header__title">搜索</view>
        </view>

        <view class="search-main" :style="'padding-top:' + navHeight + 'rpx'">
            <view class="search-bar">
                <view class="search-bar__box">
                    <text class="search-bar__icon">⌕</text>
                    <input
                        class="search-bar__input"
                        :value="desc"
                        confirm-type="search"
                        :placeholder="searchPlaceholder"
                        placeholder-class="search-bar__placeholder"
                        focus
                        @input="onInputSearch"
                        @confirm="onChangeSearch"
                    />
                    <view class="search-bar__clear" v-if="desc" @tap="clearSearch">×</view>
                </view>
            </view>

            <view class="search-summary" v-if="desc">
                <text>关键词：{{ desc }}</text>
                <text v-if="!show && selectData.length">共 {{ selectData.length }} 条</text>
            </view>

            <scroll-view class="search-scroll" :style="'height:calc(100vh - ' + (navHeight + (desc ? 176 : 128)) + 'rpx)'" :scroll-y="true" @scrolltolower="scrollLower">
                <view class="search-content">
                    <view class="state-box" v-if="show && currentPage === 1">
                        <view class="loading-ring"></view>
                        <text>检索中...</text>
                    </view>

                    <view class="state-box" v-else-if="errorMessage">
                        <view class="state-box__title">检索失败</view>
                        <view class="state-box__desc">{{ errorMessage }}</view>
                        <button class="state-box__button" @tap="retrySearch">重试</button>
                    </view>

                    <view class="state-box" v-else-if="!desc">
                        <view class="state-box__title">输入关键词开始检索</view>
                        <view class="state-box__desc">{{ searchTypeLabel }}可按名称、拼音或编码搜索</view>
                    </view>

                    <view class="state-box" v-else-if="!selectData.length">
                        <view class="state-box__title">暂无匹配{{ searchTypeLabel }}</view>
                        <view class="state-box__desc">请更换关键词后再试</view>
                    </view>

                    <view v-else class="result-list">
                        <view class="result-item" v-for="(item, index) in selectData" :key="item.id || item.diagCode || item.medID || index" :data-name="index" @tap="onClickRadio">
                            <view class="result-item__body">
                                <view class="result-item__title">
                                    <block v-for="(cell, index1) in htmltitle[code]" :key="index1">
                                        <text v-if="item[cell]" class="result-item__title-text">{{ item[cell] }}</text>
                                    </block>
                                </view>
                                <view class="result-item__tags" v-if="htmltag[code] && htmltag[code].length">
                                    <text class="result-item__tag" v-for="(cell, index1) in htmltag[code]" :key="index1">{{ item[cell] || '无库存' }}</text>
                                </view>
                                <view class="result-item__label" v-if="getLabelText(item)">{{ getLabelText(item) }}</view>
                            </view>
                            <view class="result-item__check" :class="{ 'result-item__check--active': radio === index }"></view>
                        </view>
                    </view>

                    <view class="loading-more" v-if="show && currentPage > 1">
                        <view class="loading-ring loading-ring--small"></view>
                        <text>加载中...</text>
                    </view>

                    <view class="list-footer" v-if="finished && selectData.length">已加载全部</view>
                </view>
            </scroll-view>
        </view>
    </view>
</template>

<script>
import Cache from '../../../utils/cache';
// pages/components/searchSelect/searchSelect.js
// 公共selectData查询  obj 和 code 做动态控制 其他参数统一
// 因为考虑到以后数据过多使用滚动底部懒加载的方式会重复多次请求 故请求建议全部放到组件里面 统一控制分页的请求
// 考虑到进入这个页面的可能是从嵌套了许多层之后的的组件进入 不是page页面 navigateBack 只能返回page 不适合使用普通的传值方式 所以把选中返回值传入小程序缓存Storage 任何地方使用的在所以把选中返回值传入Storage取值
import { $http } from '../../../config/https';
// H5 兼容：getApp() 在某些场景下可能返回 undefined 或不带 globalData 的 Vue 实例
const app = (typeof getApp === 'function' && getApp()) || { globalData: {} };
export default {
    components: {},
    data() {
        const statusHeight = ((app.globalData && app.globalData.height) || 0) * 2;
        return {
            focus: true,
            // 获取焦点
            selectData: [],
            // 列表选项
            code: '',
            // 接口code
            obj: {},
            // 传参对象
            pageSize: 10,
            // 条数
            currentPage: 1,
            // 页数
            desc: '',
            // 搜索内容
            searchPlaceholder: '请输入搜索关键词',
            radio: 0,
            // 选项
            options: [],
            // url参数
            htmltitle: {
                '03050019': ['medDesc', 'medPrice'],
                //医嘱名称
                '03050031': ['diagDesc', 'desc'] //诊断名称
            },

            htmltag: {
                '03050019': ['medCatDesc', 'medStock'],
                //医嘱名称
                '03050031': [] //诊断名称
            },

            htmllabel: {
                '03050019': ['medSubCatDesc'],
                //医嘱名称
                '03050031': ['diagCode'] //诊断名称
            },

            statusHeight,
            navHeight: statusHeight + 88,
            height: (app.globalData && app.globalData.height) || 0,
            show: false,
            finished: false,
            errorMessage: '',
            searchTimer: null,
            requestSeq: 0
        };
    },
    /**
     * 生命周期函数--监听页面加载
     */
    onLoad: function (options) {
        let { code } = options;
        this.setData(
            {
                code,
                options,
                searchPlaceholder: code === '03050031' ? '请输入诊断名称或编码' : '请输入医嘱名称或编码'
            }
            // 注意：不再在 onLoad 中自动调 judge()，避免 H5 端空 desc 时误触发加载层
            // 数据由用户输入关键词后通过 onChangeSearch / onInputSearch 触发
        );
        uni.getSystemInfo({
            success: (res) => {
                this.setData({});
            }
        });
    },
    /**
     * 生命周期函数--监听页面初次渲染完成
     */
    onReady: function () {
        Cache.remove('searchSelect');
    },
    /**
     * 生命周期函数--监听页面显示
     */
    onShow: function () {},
    /**
     * 生命周期函数--监听页面隐藏
     */
    onHide: function () {},
    /**
     * 生命周期函数--监听页面卸载
     */
    onUnload: function () {
        if (this.searchTimer) {
            clearTimeout(this.searchTimer);
        }
    },
    /**
     * 页面相关事件处理函数--监听用户下拉动作
     */
    onPullDownRefresh: function () {},
    /**
     * 页面上拉触底事件的处理函数
     */
    onReachBottom: function () {},
    /**
     * 用户点击右上角分享
     */
    onShareAppMessage: function () {},
    computed: {
        // 根据搜索类型动态显示文案：03050019=医嘱，03050031=诊断
        searchTypeLabel: function () {
            return this.code === '03050031' ? '诊断' : '医嘱';
        }
    },
    methods: {
        normalizeSearchValue(value) {
            if (value == null) return '';
            if (typeof value === 'object') {
                value = value.value != null ? value.value : value.detail != null ? value.detail : '';
            }
            return String(value).trim();
        },

        //判断 调取哪个接口
        judge: function (code, options) {
            let type = ''; // 草药标志
            let herbalFormID = ''; // 剂型
            let { obj, desc } = this;
            let patientData = Cache.get('patientData') || {};
            let userData = Cache.get('userData') || {};
            let { admID } = patientData;
            let { locID, userID, userCode, userName, locDesc, groupID, groupDesc, hospID, hospCode, hospDesc } = userData;
            let keyword = this.normalizeSearchValue(desc);
            if (options) {
                type = options.type;
                herbalFormID = options.herbalFormID;
            }
            switch (code) {
                case '03050019':
                    //医嘱名称跳转
                    obj = {
                        searchCode: keyword,
                        //医嘱项搜索码
                        admID: admID || '',
                        //就诊记录ID
                        logonLocID: locID || '',
                        //登录科室ID
                        userID: userID || '',
                        //登录用户ID
                        groupID: groupID || '',
                        //登录角色ID
                        medCatID: '',
                        //医嘱项大类ID
                        medSubCatID: '',
                        //医嘱项子类ID
                        hospID: hospID || '',
                        //登录医院ID
                        cmFlag: type || '',
                        //草药标志
                        judgeFlag: 'Y',
                        // 写死参数type judgeFlag
                        herbalFormID: herbalFormID || '',
                        // 使用剂型
                        notOrdSet: 'Y' // 写死参数 不查医嘱套
                    };

                    break;
                case '03050031':
                    //诊断名称跳转
                    obj = {
                        desc: keyword,
                        // 检索框内容
                        hospID: hospID || '',
                        //医院ID  session 中获取
                        CMark: this.options.CMark,
                        // 搜索中医诊断时传入N
                        admID: admID || '',
                        // 患者就诊ID session中获取
                        notOrdSet: 'Y' // 写死参数 不查医嘱套
                    };

                    break;
                default:
                    break;
            }
            this.setData(
                {
                    code,
                    obj,
                    options,
                    errorMessage: '',
                    finished: false
                },
                () => {
                    this.selectDataFun(); // 获取数据
                    // this.selectListData()   // 获取已查询数据
                }
            );
        },

        // 获取已查询数据
        selectListData: function (e) {
            let { code, obj, pageSize, currentPage } = this;
            $http.post('urlDeault', this, {
                code: code,
                data: {
                    params: [obj],
                    pagination: [
                        //页码信息
                        {
                            pageSize: pageSize,
                            currentPage: currentPage
                        }
                    ]
                },
                success: function (res) {
                    let errorCode = res.errorCode;
                    if (errorCode === '0') {
                        let data = res.result && res.result.data;
                    }
                }
            });
        },

        getRequestKeyword(obj) {
            if (!obj) return '';
            if (this.code === '03050019') {
                return this.normalizeSearchValue(obj.searchCode);
            }
            return this.normalizeSearchValue(obj.desc);
        },

        syncRequestKeyword(obj, keyword) {
            if (this.code === '03050019') {
                obj.searchCode = keyword;
            } else {
                obj.desc = keyword;
            }
        },

        // 查询诊断/医嘱列表接口
        selectDataFun: function (concat) {
            let { code, obj, pageSize, currentPage } = this;
            if (!code) {
                this.setData({ show: false });
                return false;
            }

            let userData = Cache.get('userData');
            if (!userData || !userData.userID) {
                this.setData({
                    selectData: [],
                    show: false,
                    finished: false,
                    errorMessage: '请先登录后再检索'
                });
                return false;
            }

            let keyword = this.getRequestKeyword(obj);
            if (!keyword) {
                this.setData({
                    selectData: [],
                    show: false,
                    finished: false,
                    errorMessage: ''
                });
                return false;
            }
            this.syncRequestKeyword(obj, keyword);

            let that = this;
            let seq = this.requestSeq + 1;
            this.setData({
                requestSeq: seq,
                show: true,
                errorMessage: ''
            });

            let showTimer = setTimeout(() => {
                if (that.requestSeq === seq) {
                    that.setData({
                        show: false,
                        errorMessage: '接口响应超时，请稍后重试'
                    });
                }
            }, 15000);

            $http.post(
                'urlDeault',
                this,
                {
                    code: code,
                    data: {
                        params: [obj],
                        pagination: [
                            {
                                pageSize: pageSize,
                                currentPage: currentPage
                            }
                        ]
                    },
                    success: function (res) {
                        clearTimeout(showTimer);
                        if (that.requestSeq !== seq) return;

                        let errorCode = res.errorCode;
                        if (errorCode === '0') {
                            let data = (res.result && res.result.data) || [];
                            let nextList = concat ? that.selectData.concat(data) : data;
                            that.setData({
                                selectData: nextList,
                                show: false,
                                finished: data.length < pageSize,
                                errorMessage: ''
                            });
                        } else {
                            that.setData({
                                show: false,
                                errorMessage: res.errorMessage || '检索失败，请稍后重试'
                            });
                        }
                    },
                    fail: function (res) {
                        clearTimeout(showTimer);
                        if (that.requestSeq !== seq) return;
                        that.setData({
                            show: false,
                            errorMessage: (res && res.errorMessage) || '检索失败，请稍后重试'
                        });
                    }
                },
                {
                    error: 'Y'
                }
            );
        },

        // search修改
        onChangeSearch(e) {
            let value = this.getSearchValue(e);
            if (this.searchTimer) {
                clearTimeout(this.searchTimer);
            }
            if (value) {
                this.setData(
                    {
                        desc: value,
                        currentPage: 1,
                        radio: '',
                        finished: false,
                        errorMessage: ''
                    },
                    () => {
                        let { code, options } = this;
                        this.judge(code, options); // 查询诊断列表接口
                    }
                );
            } else {
                this.setData({
                    desc: '',
                    selectData: [],
                    show: false,
                    finished: false,
                    errorMessage: ''
                });
            }
        },

        // H5环境input事件兼容
        onInputSearch(e) {
            let value = this.getSearchValue(e);
            if (value === this.desc) return;
            if (this.searchTimer) {
                clearTimeout(this.searchTimer);
            }
            if (value) {
                this.setData({
                    desc: value,
                    currentPage: 1,
                    radio: '',
                    finished: false,
                    errorMessage: ''
                });
                this.searchTimer = setTimeout(() => {
                    let { code, options } = this;
                    this.judge(code, options);
                }, 350);
            } else {
                this.setData({
                    desc: '',
                    selectData: [],
                    show: false,
                    finished: false,
                    errorMessage: ''
                });
            }
        },

        // 兼容不同环境下van-search的事件格式
        // H5 端 e = { detail: { value: 'xxx' } }，微信小程序端 e = { detail: 'xxx' }
        getSearchValue(e) {
            if (!e) return '';
            // 1. H5 端：e.detail 是对象 { value: 'xxx' }
            if (e.detail && typeof e.detail === 'object' && e.detail.value != null) {
                return this.normalizeSearchValue(e.detail.value);
            }
            // 2. 微信小程序端：e.detail 直接是字符串
            if (typeof e.detail === 'string') return this.normalizeSearchValue(e.detail);
            // 3. 原生 input 事件：e.target.value
            if (e.target && e.target.value != null) return this.normalizeSearchValue(e.target.value);
            // 4. 兜底：直接传字符串
            if (typeof e === 'string') return this.normalizeSearchValue(e);
            return '';
        },

        clearSearch() {
            if (this.searchTimer) {
                clearTimeout(this.searchTimer);
            }
            this.setData({
                desc: '',
                selectData: [],
                show: false,
                finished: false,
                errorMessage: '',
                currentPage: 1,
                radio: ''
            });
        },

        retrySearch() {
            if (!this.desc) return;
            this.setData(
                {
                    currentPage: 1,
                    finished: false,
                    errorMessage: ''
                },
                () => {
                    this.judge(this.code, this.options);
                }
            );
        },

        goBack() {
            uni.navigateBack({
                fail: function () {
                    uni.switchTab({
                        url: '/pages/tabBar/home/home'
                    });
                }
            });
        },

        getLabelText(item) {
            let labels = this.htmllabel[this.code] || [];
            return labels
                .map((cell) => item[cell])
                .filter(Boolean)
                .join('  ');
        },

        // 点击切换
        onChangeRadio(event) {
            this.setData({
                radio: event.detail
            });
        },

        // 点击切换
        onClickRadio(event, _dataset) {
            const dataset = (event && event.currentTarget && event.currentTarget.dataset) || _dataset || {};
            const name = Number(dataset.name);
            if (Number.isNaN(name)) return;
            this.setData(
                {
                    radio: name
                },
                () => {
                    this.call(name);
                }
            );
        },

        // 点击 返回上一页 传递 所选择的参数对象 使用调取上个页面的callData方法传入选择的数据
        call(name) {
            let { selectData } = this;
            let selected = selectData[name];
            if (!selected) return;
            // 数据存入Storage
            Cache.set('searchSelect', selected);
            var pages = getCurrentPages();
            var prevPage = pages[pages.length - 2]; //上一个页面
            const callPrevPage = function () {
                const target = prevPage && (prevPage.$vm || prevPage);
                if (target && typeof target.searchSelect === 'function') {
                    target.searchSelect(selected);
                }
            };
            uni.navigateBack({
                //返回
                delta: 1,
                success: function () {
                    callPrevPage();
                },
                fail: function () {
                    callPrevPage();
                }
            });
        },

        // 滚动至底端事件
        scrollLower: function () {
            if (this.show || this.finished || !this.desc || this.errorMessage) return;
            let { currentPage } = this;
            this.setData(
                {
                    currentPage: currentPage + 1
                },
                () => {
                    this.selectDataFun('true'); // 传参标识 表示是滚动加载
                }
            );
        }
    }
};
</script>
<style>
/* pages/components/searchSelect/searchSelect.wxss */

page {
    height: 100%;
    background: #f4f7fb;
}

.search-page {
    min-height: 100vh;
    background: #f4f7fb;
    color: #1f2937;
    box-sizing: border-box;
}

.search-header {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 20;
    background: #ffffff;
    box-sizing: border-box;
    box-shadow: 0 1rpx 0 rgba(15, 23, 42, 0.08);
}

.search-header__title {
    height: 88rpx;
    line-height: 88rpx;
    text-align: center;
    font-size: 36rpx;
    font-weight: 700;
    color: #111827;
}

.search-header__back {
    position: absolute;
    left: 0;
    bottom: 0;
    width: 96rpx;
    height: 88rpx;
    display: flex;
    align-items: center;
    justify-content: center;
}

.search-header__back-icon {
    color: #8a98aa;
    font-size: 64rpx;
    line-height: 1;
    transform: translateY(-2rpx);
}

.search-main {
    min-height: 100vh;
    box-sizing: border-box;
}

.search-bar {
    position: sticky;
    top: 0;
    z-index: 10;
    background: #f4f7fb;
    padding: 18rpx 24rpx 14rpx;
    box-sizing: border-box;
}

.search-bar__box {
    width: 100%;
    height: 76rpx;
    border-radius: 12rpx;
    background: #ffffff;
    border: 1rpx solid #dce5f0;
    display: flex;
    align-items: center;
    padding: 0 22rpx;
    box-sizing: border-box;
    box-shadow: 0 6rpx 16rpx rgba(15, 23, 42, 0.04);
}

.search-bar__icon {
    width: 40rpx;
    color: #8a98aa;
    font-size: 32rpx;
    line-height: 1;
}

.search-bar__input {
    flex: 1;
    min-width: 0;
    height: 72rpx;
    line-height: 72rpx;
    color: #111827;
    font-size: 29rpx;
    padding: 0 12rpx;
    box-sizing: border-box;
}

.search-bar__placeholder {
    color: #9aa6b6;
}

.search-bar__clear {
    width: 44rpx;
    height: 44rpx;
    line-height: 40rpx;
    border-radius: 50%;
    background: #eef2f7;
    color: #7b8798;
    text-align: center;
    font-size: 36rpx;
    box-sizing: border-box;
}

.search-summary {
    display: flex;
    justify-content: space-between;
    padding: 0 28rpx 12rpx;
    color: #6b7686;
    font-size: 25rpx;
    line-height: 36rpx;
    box-sizing: border-box;
}

.search-scroll {
    height: calc(100vh - 190rpx);
}

.search-content {
    padding: 0 18rpx 28rpx;
    box-sizing: border-box;
}

.state-box {
    min-height: 300rpx;
    margin: 12rpx 6rpx;
    border-radius: 12rpx;
    background: #ffffff;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    color: #7b8798;
    font-size: 28rpx;
    box-sizing: border-box;
    padding: 44rpx 32rpx;
    text-align: center;
}

.state-box__title {
    color: #1f2937;
    font-size: 30rpx;
    font-weight: 600;
    line-height: 44rpx;
}

.state-box__desc {
    margin-top: 10rpx;
    color: #7b8798;
    font-size: 26rpx;
    line-height: 38rpx;
}

.state-box__button {
    margin-top: 28rpx;
    min-width: 160rpx;
    height: 64rpx;
    line-height: 64rpx;
    border-radius: 10rpx !important;
    color: #ffffff;
    background: #1890ff;
    font-size: 28rpx;
    padding: 0 28rpx;
}

.state-box__button:after {
    border: 0;
}

.result-list {
    display: flex;
    flex-direction: column;
    gap: 14rpx;
}

.result-item {
    min-height: 112rpx;
    border-radius: 12rpx;
    background: #ffffff;
    border: 1rpx solid #e6edf5;
    padding: 20rpx 22rpx;
    box-sizing: border-box;
    display: flex;
    align-items: center;
    gap: 18rpx;
    box-shadow: 0 6rpx 16rpx rgba(15, 23, 42, 0.035);
}

.result-item__body {
    flex: 1;
    min-width: 0;
}

.result-item__title {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10rpx;
    color: #111827;
    font-size: 30rpx;
    font-weight: 600;
    line-height: 42rpx;
}

.result-item__title-text {
    word-break: break-all;
}

.result-item__tags {
    display: flex;
    flex-wrap: wrap;
    gap: 8rpx;
    margin-top: 10rpx;
}

.result-item__tag {
    line-height: 34rpx;
    border-radius: 6rpx;
    background: #fff7e6;
    color: #b26a00;
    font-size: 22rpx;
    padding: 0 10rpx;
}

.result-item__label {
    margin-top: 8rpx;
    color: #687386;
    font-size: 25rpx;
    line-height: 36rpx;
    word-break: break-all;
}

.result-item__check {
    width: 34rpx;
    height: 34rpx;
    border-radius: 50%;
    border: 2rpx solid #c8d2df;
    box-sizing: border-box;
    position: relative;
}

.result-item__check--active {
    border-color: #1890ff;
    background: #1890ff;
}

.result-item__check--active:after {
    content: "";
    position: absolute;
    left: 9rpx;
    top: 4rpx;
    width: 9rpx;
    height: 17rpx;
    border: solid #ffffff;
    border-width: 0 4rpx 4rpx 0;
    transform: rotate(45deg);
}

.loading-more,
.list-footer {
    height: 86rpx;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 12rpx;
    color: #8a98aa;
    font-size: 25rpx;
}

.loading-ring {
    width: 38rpx;
    height: 38rpx;
    border-radius: 50%;
    border: 4rpx solid #d7e6f8;
    border-top-color: #1890ff;
    animation: search-spin 0.8s linear infinite;
    margin-bottom: 18rpx;
}

.loading-ring--small {
    width: 28rpx;
    height: 28rpx;
    border-width: 3rpx;
    margin-bottom: 0;
}

@keyframes search-spin {
    from {
        transform: rotate(0deg);
    }
    to {
        transform: rotate(360deg);
    }
}
</style>
