<template>
	<view>
	<!-- 回访记录表单抽屉：使用 page-container 防止用户误退出页面；用 v-if 控制挂载/卸载 -->
	<page-container
		v-if="visible"
		:show="visible"
		:overlay="true"
		position="bottom"
		:round="true"
		@beforeleave="onClose"
		@clickoverlay="onClose"
	>
		<view class="cl-drawer">
			<view class="cl-head">
				<text class="cl-title">记录本次回访</text>
				<text class="cl-close" @click="onClose">关闭</text>
			</view>
			<scroll-view scroll-y class="cl-body">
				<view class="cl-section">
					<!-- 拨打号码：展示脱敏，form.phone 仍存完整号供提交 -->
					<view class="cl-row">
						<text class="cl-label">拨打号码</text>
						<text class="cl-value">{{ phoneDisplay || '—' }}</text>
					</view>
					<!-- 拨号时间（只读展示） -->
					<view class="cl-row">
						<text class="cl-label">拨号时间</text>
						<text class="cl-value">{{ callAtText || '—' }}</text>
					</view>
				</view>
				<!-- 回访结果：tag 横排单选（dict 驱动，颜色预计算到 computed） -->
				<view class="cl-section">
					<text class="cl-section-title">是否接通 <text class="cl-required">*</text></text>
					<view class="cl-tags">
						<view
							v-for="r in dictResultsView"
							:key="r.value"
							class="cl-tag"
							:style="{ color: r.selected ? r.color : '#6b7280', background: r.selected ? r.bgColor : '#f3f4f6', borderColor: r.selected ? r.color : '#e5e7eb' }"
							@click="form.result = r.value"
						>
							<text class="cl-tag-text">{{ r.name }}</text>
						</view>
					</view>
				</view>
				<!-- 下次回访时间：紧跟是否接通；仅选日期（年月日） -->
				<view class="cl-section">
					<text class="cl-section-title">下次回访时间</text>
					<!-- 快捷标签：3天后/7天后；选中态与 form.next_at 联动 -->
					<view class="cl-quick-tags">
						<view
							v-for="opt in nextAtQuickOptions"
							:key="opt.key"
							class="cl-tag"
							:style="{ color: opt.selected ? '#1a9b88' : '#6b7280', background: opt.selected ? '#e8f5f2' : '#f3f4f6', borderColor: opt.selected ? '#1a9b88' : '#e5e7eb' }"
							@click="onQuickPick(opt)"
						>
							<text class="cl-tag-text">{{ opt.label }}</text>
						</view>
					</view>
					<view class="cl-picker" @click="openNextAtPicker">
						<text :class="['cl-picker-text', { placeholder: !nextAtText }]">{{ nextAtText || '暂不安排' }}</text>
						<text v-if="form.next_at" class="cl-clear" @click.stop="clearNextAt">清除</text>
						<text class="cl-arrow">›</text>
					</view>
				</view>
				<!-- 回访标签：tag 横排多选（dict 驱动，颜色预计算到 computed） -->
				<view class="cl-section">
					<text class="cl-section-title">回访标签</text>
					<view class="cl-tags">
						<view
							v-for="tag in dictTagsView"
							:key="tag.value"
							class="cl-tag"
							:style="{ color: tag.selected ? tag.color : '#6b7280', background: tag.selected ? tag.bgColor : '#f3f4f6', borderColor: tag.selected ? tag.color : '#e5e7eb' }"
							@click="toggleTag(tag.value)"
						>
							<text class="cl-tag-text">{{ tag.name }}</text>
						</view>
					</view>
				</view>
				<!-- 随访结论：textarea -->
				<view class="cl-section">
					<text class="cl-section-title">随访结论</text>
					<textarea
						class="cl-textarea"
						v-model="form.conclusion"
						:maxlength="120"
						placeholder="请填写随访结论（选填）"
						placeholder-class="cl-placeholder"
					/>
				</view>
				<!-- 备注：textarea -->
				<view class="cl-section">
					<text class="cl-section-title">备注</text>
					<textarea
						class="cl-textarea"
						v-model="form.remark"
						:maxlength="200"
						placeholder="请填写备注（选填）"
						placeholder-class="cl-placeholder"
					/>
				</view>
			</scroll-view>
			<view class="cl-footer safe-area-inset-bottom">
				<view class="cl-btn cl-btn-cancel" @click="onClose"><text>取消</text></view>
				<view class="cl-btn cl-btn-ok" @click="onSubmit"><text>提交</text></view>
			</view>
		</view>
	</page-container>
	<!-- 下次回访时间 picker：uView 时间模式（只到天，不选时分） -->
	<u-picker
		v-model="nextAtPickerShow"
		mode="time"
		:params="nextAtParams"
		confirm-text="确定"
		@confirm="onNextAtConfirm"
		@cancel="nextAtPickerShow = false"
	></u-picker>
	</view>
</template>

<script>
/**
 * 回访记录表单抽屉
 * 用途：在就诊人详情页（抽屉/页面）拨号后或手动点击"记录本次回访"时打开
 * 字段：phone/call_at(由父组件预填) + result/tags/conclusion/remark/next_at
 * 数据源：dict（回访结果/回访标签）从后台维护的 xk_patient_call_log_dict 表加载
 */
import { createPatientCallLog, getPatientCallLogDict } from '@/api/userPatientProfile.js';

/** 兜底数据：dict 接口失败时使用，保证 UI 不崩 */
const FALLBACK_RESULTS = [
	{ value: 'connected', name: '接通', color: '#1a9b88' },
	{ value: 'no_answer', name: '未接', color: '#b45309' },
	{ value: 'hangup', name: '挂断', color: '#b91c1c' },
	{ value: 'invalid', name: '号码错误', color: '#6b7280' },
];
const FALLBACK_TAGS = [
	{ value: 'care', name: '关怀', color: '#6acdbb' },
	{ value: 'condition', name: '病情', color: '#ef4444' },
	{ value: 'medication', name: '用药提醒', color: '#3b82f6' },
	{ value: 'review', name: '复诊提醒', color: '#f59e0b' },
	{ value: 'complaint', name: '投诉处理', color: '#8b5cf6' },
];

/** 时间选择器精度：仅年月日（用户要求选日期即可，不选时分） */
const NEXT_AT_PARAMS = {
	year: true,
	month: true,
	day: true,
	hour: false,
	minute: false,
	second: false,
};

export default {
	name: 'CallLogDrawer',
	props: {
		/** 控制抽屉显隐，v-if 挂载 */
		visible: { type: Boolean, default: false },
		/** 就诊人ID */
		upId: { type: [Number, String], default: 0 },
		/**
		 * 预填数据：拨号场景下父组件传入 { phone, call_at }
		 * 手动点击场景不传，phone/call_at 留空，由用户填写
		 */
		prefill: { type: Object, default: () => ({}) },
	},
	data() {
		return {
			submitting: false,
			form: {
				phone: '',
				call_at: 0,
				result: '',
				tags: [],
				conclusion: '',
				remark: '',
				next_at: 0,
			},
			// dict：后台维护的结果/标签列表，含 color
			dictResults: FALLBACK_RESULTS,
			dictTags: FALLBACK_TAGS,
			nextAtParams: NEXT_AT_PARAMS,
			nextAtPickerShow: false,
		};
	},
	computed: {
		/**
		 * 拨打号码脱敏展示：保留前3后4，中间 ****
		 * form.phone 仍为完整号码，提交时不脱敏
		 */
		phoneDisplay() {
			const phone = String(this.form.phone || '').trim();
			if (!phone) return '';
			if (phone.length < 7) return phone;
			return phone.slice(0, 3) + '****' + phone.slice(-4);
		},
		/** 拨号时间格式化展示（call_at 为秒级时间戳） */
		callAtText() {
			if (!this.form.call_at) return '';
			return this.formatTimestamp(Number(this.form.call_at), true);
		},
		/** 下次回访时间展示（仅日期） */
		nextAtText() {
			if (!this.form.next_at) return '';
			return this.formatTimestamp(Number(this.form.next_at), false);
		},
		/**
		 * 回访结果列表（带 selected 标记 + 浅色背景 bgColor）
		 * 注意：小程序模板 :style 不允许调函数，故把颜色计算放进 computed
		 */
		dictResultsView() {
			const cur = this.form.result;
			return this.dictResults.map((r) => {
				const color = r.color || '#6acdbb';
				return {
					value: r.value,
					name: r.name,
					color,
					bgColor: this.hexToRgba(color, 0.1),
					selected: r.value === cur,
				};
			});
		},
		/** 回访标签列表（同上） */
		dictTagsView() {
			const tags = this.form.tags || [];
			return this.dictTags.map((t) => {
				const color = t.color || '#6acdbb';
				return {
					value: t.value,
					name: t.name,
					color,
					bgColor: this.hexToRgba(color, 0.1),
					selected: tags.indexOf(t.value) >= 0,
				};
			});
		},
		/**
		 * 下次回访时间快捷选项：3天后 / 7天后
		 * selected 标记是否与当前 form.next_at 命中同一天（避免时分差异导致不选中）
		 */
		nextAtQuickOptions() {
			const cur = this.form.next_at;
			const curDay = cur ? this.dayStartTs(cur) : 0;
			return [
				{ key: '3d', label: '3天后', days: 3, ts: this.daysLaterTs(3) },
				{ key: '7d', label: '7天后', days: 7, ts: this.daysLaterTs(7) },
			].map((o) => Object.assign({}, o, {
				selected: cur > 0 && this.dayStartTs(o.ts) === curDay,
			}));
		},
	},
	watch: {
		/**
		 * v-if 挂载时 visible 已是 true，用 immediate 同步初始化表单 + 加载 dict
		 */
		visible: {
			immediate: true,
			handler(val) {
				if (val) {
					this.initForm();
					this.loadDict();
				}
			},
		},
	},
	methods: {
		/** 打开抽屉时根据 prefill 初始化表单 */
		initForm() {
			const pre = this.prefill || {};
			this.submitting = false;
			this.form = {
				phone: String(pre.phone || ''),
				call_at: Number(pre.call_at || 0),
				result: '',
				tags: [],
				conclusion: '',
				remark: '',
				next_at: 0,
			};
			this.nextAtPickerShow = false;
		},
		/** 拉取后台维护的回访结果/标签字典，加载失败兜底用 FALLBACK */
		async loadDict() {
			try {
				const wrap = await getPatientCallLogDict();
				const body = wrap && wrap.res ? wrap.res : null;
				const payload = body && body.result ? body.result : null;
				if (payload) {
					if (Array.isArray(payload.results) && payload.results.length) {
						this.dictResults = payload.results;
					}
					if (Array.isArray(payload.tags) && payload.tags.length) {
						this.dictTags = payload.tags;
					}
				}
			} catch (e) {
				// 静默兜底，使用 FALLBACK 数据保证 UI 可用
			}
		},
		/** 关闭抽屉 */
		onClose() {
			if (this.submitting) return;
			this.$emit('update:visible', false);
			this.$emit('close');
		},
		/** 判断标签是否已选中 */
		isTagChecked(value) {
			return this.form.tags.indexOf(value) >= 0;
		},
		/** 切换标签选中态 */
		toggleTag(value) {
			const idx = this.form.tags.indexOf(value);
			if (idx >= 0) {
				this.form.tags.splice(idx, 1);
			} else {
				this.form.tags.push(value);
			}
		},
		/** hex(#RRGGBB) -> rgba 字符串，alpha 控制浅色背景 */
		hexToRgba(hex, alpha) {
			const m = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex || '');
			if (!m) return `rgba(106,205,187,${alpha})`;
			const r = parseInt(m[1], 16);
			const g = parseInt(m[2], 16);
			const b = parseInt(m[3], 16);
			return `rgba(${r},${g},${b},${alpha})`;
		},
		/** 打开下次回访时间选择器 */
		openNextAtPicker() {
			this.nextAtPickerShow = true;
		},
		/**
		 * 下次回访时间确认
		 * uView u-picker mode=time 的 confirm 回调返回对象：
		 *   { year, month, day, hour, minute, second, timestamp }
		 * 其中 timestamp 为秒级时间戳；仅选年月日时，时间部分为当天 0 点
		 */
		onNextAtConfirm(e) {
			if (e && typeof e.timestamp === 'number' && e.timestamp > 0) {
				// 优先用 uView 提供的秒级时间戳
				this.form.next_at = e.timestamp;
			} else if (e && e.year) {
				// 兜底：手动拼接 YYYY-MM-DD 再解析（兼容 Safari/iOS）
				const pad = (n) => (Number(n) < 10 ? '0' + Number(n) : '' + n);
				const text = `${e.year}-${pad(e.month)}-${pad(e.day)}`;
				this.form.next_at = Math.floor(Date.parse(text.replace(/-/g, '/')) / 1000) || 0;
			} else {
				this.form.next_at = 0;
			}
			this.nextAtPickerShow = false;
		},
		/** 清除下次回访时间 */
		clearNextAt() {
			this.form.next_at = 0;
		},
		/**
		 * 点击快捷标签：再次点击同一天则取消；否则写入"今天起 N 天后 00:00:00"
		 * @param opt {key,label,days,ts,selected}
		 */
		onQuickPick(opt) {
			if (opt && opt.selected) {
				this.form.next_at = 0;
			} else if (opt) {
				this.form.next_at = this.daysLaterTs(opt.days);
			}
		},
		/** 当前时间 + N 天的当天 00:00:00 秒级时间戳 */
		daysLaterTs(days) {
			const n = Number(days) || 0;
			const now = new Date();
			const d = new Date(now.getFullYear(), now.getMonth(), now.getDate() + n, 0, 0, 0);
			return Math.floor(d.getTime() / 1000);
		},
		/** 取某时间戳所在自然日 00:00:00 的秒级时间戳（同日判断用） */
		dayStartTs(ts) {
			const d = new Date(ts * 1000);
			const start = new Date(d.getFullYear(), d.getMonth(), d.getDate(), 0, 0, 0);
			return Math.floor(start.getTime() / 1000);
		},
		/**
		 * 时间戳 -> 字符串
		 * @param ts 秒级时间戳
		 * @param withTime true 返回 YYYY-MM-DD HH:mm；false 仅 YYYY-MM-DD
		 */
		formatTimestamp(ts, withTime) {
			if (!ts) return '';
			const d = new Date(ts * 1000);
			const pad = (n) => (n < 10 ? '0' + n : '' + n);
			const ymd = `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
			return withTime ? `${ymd} ${pad(d.getHours())}:${pad(d.getMinutes())}` : ymd;
		},
		/** 提交表单 */
		async onSubmit() {
			if (this.submitting) return;
			if (!this.form.result) {
				uni.showToast({ title: '请选择是否接通', icon: 'none' });
				return;
			}
			if (!this.upId) {
				uni.showToast({ title: '缺少就诊人信息', icon: 'none' });
				return;
			}
			this.submitting = true;
			uni.showLoading({ title: '提交中...', mask: true });
			try {
				const payload = {
					phone: this.form.phone,
					call_at: this.form.call_at,
					result: this.form.result,
					tags: this.form.tags,
					conclusion: this.form.conclusion,
					remark: this.form.remark,
					next_at: this.form.next_at,
				};
				const wrap = await createPatientCallLog(this.upId, payload);
				const ok = !!(wrap && wrap.ok);
				uni.hideLoading();
				if (!ok) {
					uni.showToast({ title: '提交失败', icon: 'none' });
					return;
				}
				uni.showToast({ title: '已记录', icon: 'success' });
				this.$emit('success');
				this.$emit('update:visible', false);
				this.$emit('close');
			} catch (e) {
				uni.hideLoading();
				uni.showToast({ title: '网络异常', icon: 'none' });
			} finally {
				this.submitting = false;
			}
		},
	},
};
</script>

<style lang="scss" scoped>
.cl-drawer {
	height: 80vh;
	background: #f9fafb;
	display: flex;
	flex-direction: column;
	padding-bottom: env(safe-area-inset-bottom);
	box-sizing: border-box;
}
.cl-head {
	display: flex;
	justify-content: space-between;
	align-items: center;
	padding: 28rpx 32rpx;
	background: #fff;
	border-bottom: 1rpx solid #f0f0f0;
	flex-shrink: 0;
}
.cl-title { font-size: 30rpx; font-weight: 600; color: #111827; }
.cl-close { font-size: 26rpx; color: #6acdbb; }
.cl-body {
	flex: 1;
	min-height: 0;
	padding: 16rpx 24rpx;
	box-sizing: border-box;
}
.cl-section {
	background: #fff;
	border-radius: 14rpx;
	padding: 20rpx 24rpx;
	margin-bottom: 16rpx;
}
.cl-section-title {
	display: block;
	font-size: 26rpx;
	font-weight: 600;
	color: #1f2937;
	margin-bottom: 16rpx;
}
.cl-required { color: #dc2626; margin-left: 4rpx; }
.cl-row {
	display: flex;
	justify-content: space-between;
	align-items: center;
	padding: 8rpx 0;
}
.cl-label { font-size: 24rpx; color: #9ca3af; }
.cl-value { font-size: 26rpx; color: #374151; }
.cl-picker {
	display: flex;
	align-items: center;
	gap: 12rpx;
	border: 1rpx solid #e5e7eb;
	border-radius: 12rpx;
	padding: 18rpx 20rpx;
}
.cl-picker-text { flex: 1; font-size: 26rpx; color: #111827; }
.cl-picker-text.placeholder { color: #9ca3af; }
.cl-clear { font-size: 24rpx; color: #6acdbb; padding: 0 12rpx; }
.cl-arrow { font-size: 32rpx; color: #9ca3af; line-height: 1; }
.cl-tags {
	display: flex;
	flex-wrap: wrap;
	gap: 16rpx;
}
.cl-quick-tags {
	display: flex;
	flex-wrap: wrap;
	gap: 16rpx;
	margin-bottom: 16rpx;
}
.cl-tag {
	padding: 10rpx 24rpx;
	border-radius: 24rpx;
	background: #f3f4f6;
	border: 1rpx solid #e5e7eb;
}
.cl-tag-text { font-size: 24rpx; color: #6b7280; }
.cl-textarea {
	width: 100%;
	box-sizing: border-box;
	background: #f9fafb;
	border: 1rpx solid #e5e7eb;
	border-radius: 12rpx;
	padding: 18rpx 20rpx;
	font-size: 26rpx;
	color: #111827;
	min-height: 120rpx;
}
.cl-placeholder { color: #9ca3af; font-size: 26rpx; }
.cl-footer {
	display: flex;
	gap: 16rpx;
	padding: 16rpx 24rpx 24rpx;
	background: #fff;
	border-top: 1rpx solid #f0f0f0;
	flex-shrink: 0;
}
.cl-btn {
	flex: 1;
	display: flex;
	justify-content: center;
	align-items: center;
	height: 80rpx;
	border-radius: 40rpx;
	font-size: 28rpx;
}
.cl-btn-cancel { background: #f3f4f6; color: #6b7280; }
.cl-btn-ok { background: #6acdbb; color: #fff; }
</style>
