浅时光吖~  
生活明朗,万物可爱,加油~

最近有一个需求,是要在前端做一个地址识别功能。。。确认不交给后台调接口去用ai识别吗?

看需求图:(识别出来的地址要给勾选上,这是个四级联动)

 

 

 

说一下解决方案:先将输入的地址格式化,去掉空格,统一把中文标点转换成英文,去掉换行符等。。。然后对字符串进行切割,进行强匹配,输出匹配上的数组。

地址识别组件:

 

  

import React, { FC, useState } from "react";
import { FormShape, createForm } from "@components/Form";
import { Textarea } from "@components/Input";
import Tooltip from "@components/Tooltip";
import { errorTip, successTip } from "@components/Tips";

type DistinguishProps = {
    form: FormShape;
    addressCheck?: (...args) => void;
    addressData: any;
};

const Distinguish: FC<DistinguishProps> = ({ form, addressCheck, addressData }) => {
    const [successAdd, setSuccessAdd] = useState([]);
    const [isSuccess, setIsSuccess] = useState("");
    const re1 = /[;]/;
    const re2 = /[:]/;

    // 处理识别数据
    const dealText = value => {
        if (!value) return;
        // 格式化,转换成英文字符,方便切割
        let str = value
            .replace(/:/g, ":")
            .replace(/;/g, ";")
            .replace(/[\r\n]/g, "")
            .replace(/\t/g, " ");
        let newData1 = [];
        let newData2 = [];
        let newData3 = [];
        try {
            if (re1.test(str)) {
                newData1 = str.split(";");
                newData1.forEach(item1 => {
                    item1 ? newData2.push(item1) : " ";
                });
                newData2.forEach(item2 => {
                    if (re2.test(item2)) {
                        newData3.push({
                            [item2.split(":")[0]]: item2.split(":")[1].split(" "),
                        });
                    } else {
                        newData3.push({ [item2]: [] });
                    }
                });
            } else {
                if (re2.test(str)) {
                    newData1 = str.split(":");
                    newData1.forEach(item1 => {
                        item1 ? newData2.push(item1) : " ";
                    });
                    newData3.push({
                        [newData2[0]]: newData2[1].split(" "),
                    });
                } else {
                    newData3.push({ [str]: [] });
                }
            }
            return newData3;
        } catch (e) {
            errorTip("地址识别失败!请按照提示的格式输入地址信息。");
            setSuccessAdd([]);
        }
    };

    // 数组对象去重,合并
    const mergeData = value => {
        let initArr = [];
        let initData = {};
        let data = xt.cloneDeep(value); //深拷贝
        if (data.length > 0) {
            data.forEach(item => {
                if (typeof item == "string") {
                    initArr.push(item);
                } else {
                    let map = item;
                    for (let k in map) {
                        if (k != null && k != "null") {
                            if (initData.hasOwnProperty(k)) {
                                initData[k] += "," + map[k];
                            } else {
                                initData[k] = map[k];
                            }
                        }
                    }
                }
            });
        }
        Object.keys(initData).forEach(key => {
            if (initData[key]) {
                let a = Array.from(new Set(initData[key].split(","))).join(",");
                initArr.push({ [key]: a });
            } else {
                initArr.push(key);
            }
        });
        return initArr;
    };

    // 地址匹配
    const addressPick = (val: any) => {
        let errAddress = []; // 识别失败地址
        let sucessAddress = []; // 识别成功地址
        let inputAddress = val; // 输入的地址
        let propsData = xt.cloneDeep(addressData); // 识别选中的地址
        try {
            inputAddress.forEach(item => {
                // @ts-ignore
                if (Object.values(item)?.flat().length) {
                    // 选中区下面的街道
                    Object.values(item)
                        // @ts-ignore
                        .flat()
                        .forEach(address => {
                            propsData.forEach(data => {
                                // @ts-ignore
                                if (data.nameCN == xt.nesGame(Object.keys(item)?.flat()[0])) {
                                    data?.childrenStreet.forEach(a => {
                                        if (a.nameCN == xt.nesGame(address)) {  // xt.nesGame去掉空格
                                            sucessAddress.push({ [data.nameCN]: address });
                                            a.choose = true;
                                        }
                                    });
                                }
                            });
                        });
                } else {
                    // 直接选中区以及下面所有的街道
                    propsData.forEach(data => {
                        // @ts-ignore
                        if (data.nameCN == xt.nesGame(Object.keys(item)?.flat()[0])) {
                            data.choose = true;
                            data?.childrenStreet.forEach(a => {
                                a.choose = true;
                            });
                            // @ts-ignore
                            sucessAddress.push(xt.nesGame(Object.keys(item)?.flat()[0]));
                        }
                    });
                }
            });
            if (sucessAddress.length > 0) {
                setIsSuccess("识别成功地址");
                successTip("识别成功");
                addressCheck(Array.from(new Set(sucessAddress)));
                setSuccessAdd(mergeData(sucessAddress)); // 识别成功地址
            } else {
                setIsSuccess("地址识别失败!请检查后再试");
                setSuccessAdd([]);
            }
        } catch (e) {
            errorTip("地址匹配失败!请检查后再试");
            setSuccessAdd([]);
        }
    };

    // 提交给父组件
    // 宝安区:福永街道 石岩街道  航城街道  福海街道 西乡街道 西乡街道;罗湖区
    const submit = () => {
        setIsSuccess("");
        form.validateFields((error, value: any) => {
            if (error) return;
            addressPick(dealText(value.note));
        });
    };

    const cancel = () => {
        form.resetFields();
        setSuccessAdd([]);
        setIsSuccess("");
    };

    return (
        <div
            className="pb-20"
            style={{ border: "1px solid #eaedf3", borderRadius: "4px", backgroundColor: "#fff" }}
        >
            <Textarea
                form={form}
                fieldName="note"
                textareaStyle={{ border: "none" }}
                placeholder={
                    "请粘贴文本至此处,自动识别区、县、街道名称并选中,若有多个街道请以区名或县名加冒号开头,多个街道以空格隔开,以分号结束,若需选中整个区或县所有街道则直接输入区名或县名以分号结束。\n例:坪山区:坪山街道 坑梓街道;南山区;"
                }
                style={{ width: "100%", border: "none" }}
                maxLength={300}
                showError="down"
                rules={false}
                normalize={(val, prev) => {
                    if (val.length > 300) return prev.trim();
                    if (!val.trim().length || val.length === 300) return val.trim();
                    return val;
                }}
            />
            <div className="mt-20  pr-20 flex-align-center" style={{ paddingLeft: "15px" }}>
                <button className="button-primary mr-20" onClick={submit}>
                    识别文本
                </button>
                <button className="button-default" onClick={cancel}>
                    清空
                </button>
                <div className="ml-30">
                    <span
                        className="mr-5 font12 c-606266"
                        style={{ color: isSuccess == "识别成功地址" ? "" : "#FF6666" }}
                    >
                        {isSuccess}
                    </span>
                    {!!successAdd.length && (
                        <Tooltip
                            overlay={
                                <>
                                    {successAdd.map((val, index) => {
                                        if (typeof val === "string") {
                                            return <p>{val};</p>;
                                        } else {
                                            return (
                                                <p>
                                                    {Object.keys(val)[0]}:
                                                    {Array.from(new Set(Object.values(val))).join(
                                                        ","
                                                    )}
                                                </p>
                                            );
                                        }
                                    })}
                                </>
                            }
                        >
                            <i className={"wsf-icon-question"} />
                        </Tooltip>
                    )}
                </div>
            </div>
        </div>
    );
};

export default createForm()(Distinguish);

  

 

posted on 2022-09-28 09:54  浅时光吖~  阅读(489)  评论(0编辑  收藏  举报