| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309 |
- // module/chats/components/message-select/message-select.ts
- interface Option {
- id: string;
- name: string;
- checked?: boolean;
- options: Option[] | null;
- }
- interface HandleEvent {
- mark: {
- type: "sub" | "options";
- index: number;
- item: Option;
- };
- }
- Component({
- properties: {
- payload: {
- type: Object,
- value: { title: "", multiple: false, options: [] },
- result: "",
- belongNew: null,
- },
- active: { type: Boolean, value: false },
- },
- data: {
- options: [] as Option[],
- subOptions: [] as Option[],
- subMultiple: false,
- itemHeight: 48,
- result: "",
- hasSelected: false,
- leftTitle: "都没有",
- rightTitle: "提交",
- initialOptions: [] as Option[], // 保存初始状态
- hasChanged: false, // 记录是否发生了变化
- },
- lifetimes: {
- attached() {
- if (this.data.payload.belongNew) {
- this.setData({
- leftTitle: "都没有",
- rightTitle: "提交",
- });
- } else {
- this.setData({
- leftTitle: "无变化",
- rightTitle: "完成",
- });
- }
- },
- },
- observers: {
- "payload.options"(options: any) {
- this.setData({ options });
- // 保存初始状态(深拷贝)
- const initialOptions = JSON.parse(JSON.stringify(options));
- this.setData({ initialOptions });
- },
- options(options: AnyArray) {
- const hasSelected = options
- .filter((option: any) => !option.hide)
- .some((option: any) => option.checked);
- // 检测是否与初始状态不同
- const hasChanged = this._checkOptionsChanged(
- options,
- this.data.initialOptions
- );
- this.setData({
- hasSelected,
- hasChanged,
- });
- },
- },
- methods: {
- // 检测选项是否发生变化
- _checkOptionsChanged(
- currentOptions: Option[],
- initialOptions: Option[]
- ): boolean {
- if (!initialOptions || initialOptions.length === 0) {
- return false;
- }
- // 比较主选项的选中状态
- for (let i = 0; i < currentOptions.length; i++) {
- const current = currentOptions[i];
- const initial = initialOptions[i];
- if (!initial) continue;
- // 比较主选项的checked状态
- if (current.checked !== initial.checked) {
- return true;
- }
- // 如果有子选项,比较子选项的选中状态
- if (current.options && initial.options) {
- for (let j = 0; j < current.options.length; j++) {
- const currentSub = current.options[j];
- const initialSub = initial.options[j];
- if (!initialSub) continue;
- if (currentSub.checked !== initialSub.checked) {
- return true;
- }
- }
- }
- }
- return false;
- },
- handleTop(event: HandleEvent) {
- const {
- mark: { item },
- } = event;
- if (!item || !this.data.active) return;
- const index = this.data.options.findIndex(
- (option) => option.id === item.id
- );
- // 如果当前项已选中且已有已选中的子项,则直接弹出子项程度选择弹窗以便修改
- const itemInState: any = this.data.options[index];
- const hasSubOptions = itemInState?.options?.filter(
- (o: any) => !o?.hide
- ).length;
- const hasAnySubChecked = itemInState?.options?.some(
- (o: any) => o?.checked
- );
- if (itemInState?.checked && hasSubOptions && hasAnySubChecked) {
- this.setData({
- subTitle: itemInState.name,
- subOptions: itemInState.options,
- subMultiple: itemInState.css === "checkbox",
- });
- this.onCancel = () => {
- this.setData({ subOptions: [] });
- };
- this.onConfirm = () => {
- if (!this.data.subOptions.some((option) => option.checked)) {
- wx.showToast({ title: "请至少选择一项", icon: "error" });
- } else {
- const options = this.data.options;
- options[index].options = this.data.subOptions;
- this.setData({ subOptions: [], options });
- // 单选场景:选择/修改子程度后直接提交
- if (!this.data.payload.multiple) {
- this.onSubmit();
- }
- }
- };
- return;
- }
- const multiple = this.data.payload.multiple;
- const checked = !item.checked;
- const options = this._handle(this.data.options, item, index, multiple);
- this.setData({ options });
- // 注释掉自动提交的逻辑,让用户可以继续选择症状程度
- if (checked && !multiple) {
- this.onSubmit();
- }
- },
- handleSub(event: HandleEvent) {
- const {
- mark: { item },
- } = event;
- if (!item || !this.data.active) return;
- const index = this.data.subOptions.findIndex(
- (option) => option.id === item.id
- );
- const multiple = this.data.subMultiple;
- const checked = !item.checked;
- const subOptions = this._handle(
- this.data.subOptions,
- item,
- index,
- multiple
- );
- this.setData({ subOptions });
- // 检查是否所有症状程度都被取消选中
- const hasAnySubChecked = subOptions.some((option) => option.checked);
- if (!hasAnySubChecked) {
- // 如果没有任何症状程度被选中,则取消整个症状的选中状态
- const mainIndex = this.data.options.findIndex(
- (option) => option.name === this.data.subTitle
- );
- if (mainIndex !== -1) {
- const options = this.data.options;
- options[mainIndex].checked = false;
- options[mainIndex].options = options[mainIndex].options?.map(
- (option: any) => {
- if (!option?.hide) option.checked = false;
- return option;
- }
- );
- // 关闭当前弹窗,避免遮挡导致切换其它症状时看起来未选中
- this.setData({ options, subOptions: [], subTitle: "" });
- return;
- }
- }
- // 注释掉自动关闭弹窗的逻辑,让用户可以继续修改症状程度
- if (checked && !multiple) {
- this.onConfirm();
- }
- },
- _handle(
- options: Option[],
- item: Option,
- index: number,
- multiple?: boolean
- ) {
- const checked = !item.checked;
- if (checked) {
- const fn = () => {
- if (multiple) {
- options[index].checked = checked;
- } else {
- options.forEach((option) => {
- option.checked = option.id === item.id;
- });
- }
- return options;
- };
- if (item.options?.filter((option) => !(<any>option)?.hide).length) {
- this.setData({
- subTitle: item.name,
- subOptions: item.options,
- subMultiple: (<any>item).css === "checkbox",
- });
- this.onCancel = () => {
- this.setData({ subOptions: [] });
- };
- this.onConfirm = () => {
- if (!this.data.subOptions.some((option) => option.checked)) {
- wx.showToast({ title: "请至少选择一项", icon: "error" });
- } else {
- const options = fn();
- options[index].options = this.data.subOptions;
- this.setData({ subOptions: [], options });
- // 单选场景:选择子程度“确定”后直接提交
- if (!this.data.payload.multiple) {
- this.onSubmit();
- }
- }
- };
- } else {
- return fn();
- }
- } else {
- options[index].checked = !item.checked;
- if (item.options)
- options[index].options = item.options.map((option) => {
- if (!(<any>option)?.hide) option.checked = !item.checked;
- return option;
- });
- }
- return options;
- },
- onCancel() {},
- onConfirm() {},
- onSubmit() {
- if (this.data.result) return;
- if (!this.data.hasSelected) {
- wx.showToast({ title: "请至少选择一项", icon: "error" });
- } else {
- const result = this.data.options
- .filter((item: any) => item?.checked && !item?.hide)
- .map((option: any) => {
- const sub = option.options
- ?.filter((item: any) => item?.checked && !item?.hide)
- .map((item: any) => item.name)
- .join(", ");
- return [option.name, sub].filter(Boolean).join(": ");
- })
- .join("; ");
- this.setData({ result });
- this.triggerEvent("next", { options: this.data.options });
- }
- },
- onSkip() {
- if (this.data.result) return;
- // 如果是新用户(belongNew为true),使用原来的逻辑
- if (this.data.payload.belongNew) {
- if (this.data.hasSelected) return;
- if (!this.data.payload.required) {
- this.setData({ result: "都没有" });
- this.triggerEvent("next", { options: this.data.options });
- }
- } else {
- // 如果是老用户(belongNew为false),检查是否发生了变化
- if (this.data.hasChanged) {
- // 如果发生了变化,不允许点击"无变化"
- // wx.showToast({ title: "症状已发生变化,请重新选择", icon: "none" });
- return;
- }
- // 如果没有变化,允许点击"无变化"
- this.setData({ result: "无变化" });
- this.triggerEvent("next", { options: this.data.options });
- }
- },
- },
- });
|