实现自定义类型比较的三种改写方法 -- 以set<Point>为例

前置

模板 – 打印

CppBaseDay21

重载 <<

os 是泛化的 std::ostream

  • operator<< 函数中,osstd::ostream 的引用,这意味着它可以代表任何具体的输出流,例如 std::coutstd::ofstream(文件输出流)、std::ostringstream(字符串输出流)等。
  • 当你向 operator<< 传递 std::cout 时,os 实际上就是 std::cout 的引用;但你也可以将其他流传递给 os,例如文件流对象或字符串流对象。

cout 是特定的 std::ostream 实例

  • std::cout 是一个具体的 std::ostream 实例,它与标准输出(通常是终端/控制台)相关联。你可以直接用 std::cout 来向屏幕打印消息。
  • cout 不能替代 os,因为 os 可以是任何输出流,而 cout 仅指向标准输出。

使用namespace std { }的原因

当我们对标准库模板进行特化时,必须将特化放入 std 命名空间,因为这些模板是在 std 命名空间中定义的。如果不放在 std 命名空间中,编译器将无法将其视为对标准模板的特化,而是会当成一个独立的新模板。


第一种方式 – 模板的特化

类模板特化 template<> struct less<Point>

//类模板定义
template <class/typename T, ...>
class 类名{
//类定义......
};
//chatgpt给出的示例:
namespace std {
    template <class T>	//less<Point> 是对模板 less<T> 的特化,Point 是 T 的具体类型
    struct less {
       ……
    };
}

//代码中的写法 
template <>
struct less<Point>//模板的特化
{
	……
}
  • template<>:这是模板特化的语法,表示我们将为模板类 std::less 提供一个特化版本,用于处理 Point 类型。

  • struct less<Point>:我们在 std::less 模板中为 Point 类型提供特化,即定义一个新的规则用于比较 Point 对象。。

这个特化会覆盖默认的 std::less 行为–在标准库中,std::less 是一个类模板,用于定义对象之间的比较操作(通常是 < 运算符)。它的默认实现会使用 < 运算符来比较对象。

struct less<Point> 是对 std::less 这个模板类的特化,这里的 Point 具体化了模板参数 T

less 是类名,T 是一个类型参数。这个模板类可以用来创建不同类型的比较器,例如 less<int>less<double> 等。

  • operator():这是重载的函数调用运算符,定义了 less<Point> 如何比较两个 Point 对象。在这个例子中,我们首先比较 x 坐标,如果 x 坐标相等,则比较 y 坐标。

为什么要末尾要加const–成为const成员函数被调用

const/非const对象 以及 const/非const函数

在 const 对象上调用成员函数

  • 只能调用 const 成员函数。
  • 不能调用非常量成员函数。

在非常量对象上调用成员函数

  • 可以调用 const 和非 const 成员函数(优先,没有再调用const版本)。
chatgpt例子
class MyClass {
public:
    int value;

    // 非 const 成员函数
    void setValue(int v) {
        value = v; // 修改值
    }

    // const 成员函数
    int getValue() const {
        return value; // 只读
    }
};

int main() {
    MyClass obj; // 非 const 对象
    obj.setValue(5); // 可以调用
    int val = obj.getValue(); // 可以调用

    const MyClass constObj; // const 对象
    // constObj.setValue(10); // 错误,不能调用非 const 成员函数
    int constVal = constObj.getValue(); // 可以调用 const 成员函数

    return 0;
}
set源码中的成员函数operator()

看看吧。。。主要看图,格式就是这样要求的。。。

STL 容器(如 std::setstd::map)通常会使用传递的比较函数来比较元素。为了保证这些比较函数能够在使用时不改变容器中元素的状态,STL 要求这些函数必须是 可调用的(invocable)并且应该是 const 的。

以下是个人猜想。。。

set底层是const修饰的,因此set的对象只能调用const 成员函数

所以bool operator()(const Point &lhs,const Point &rhs)后面要加 const

//error
bool operator()(const Point &lhs,const Point &rhs) {……}
bool operator()(const Point &lhs,const Point &rhs) const {……}

在这里插入图片描述

//默认的模板
#if 0
namespace std
{
template <class T>
struct less
{
    bool operator()(const T &lhs, const T &rhs) const
    {
        return lhs < rhs;
    }
};
}//end of namespace std
#endif

形式

template <>
struct less<Point>//模板的特化
{
	……
}

代码1

在这里插入图片描述

#include <math.h>
#include <iostream>
#include <set>

using std::cout;
using std::endl;
using std::set;

//模板 -- 打印
template <typename Container>    //typename - class 
void display(const Container & con){
    for(auto & elem : con){
        cout << elem << " ";
    }
    cout << endl;
}

class Point
{
public:
    Point(int ix = 0, int iy = 0)
    : _ix(ix)
    , _iy(iy)
    {
    }

    //计算点到原点的距离
    float getDistance() const
    {
        return hypot(_ix, _iy);
    }

    int getX() const
    {
        return _ix;
    }

    int getY() const
    {
        return _iy;
    }

    ~Point()
    {
    }

    friend std::ostream & operator<<(std::ostream & os,const Point & rhs);   //Point

private:
    int _ix;
    int _iy;
};

//由于是自定义模板,需要重载 <<
//同时由于需要访问Point类的私有成员,因此在Point类中需要把该函数声明为友元
std::ostream & operator<<(std::ostream & os,const Point & rhs){
    os << "(" << rhs._ix << "," << rhs._iy << ")";
    return os;
}


//第一种 -- 模板的特化
namespace std
{
template <>
struct less<Point>  //less是类名,T是一个类型参数。例如 less<int>、less<double> 等。
{
    //比较2个Point类对象
    bool operator()(const Point &lhs,const Point &rhs) const
    {   
        cout << "template<> struct less" << endl;
        // x 和 y均采用升序的方式比较大小
        if(lhs.getX() < rhs.getX())
        {
            return true;
        }else if(lhs.getX() == rhs.getX()){
            if(lhs.getY() < rhs.getY()){
                return true;
            }else{
                return false;
            }
        }
        else    //lhs.getX() > rhs.getX()
        {
            return false;
        }
    } 
};
}   //end of namespace std


//第二种 -- 运算符重载


//第三种 -- 函数对象



void test0(){
    set<Point> number = {
        Point(1, 2),
        Point(-1, 2),
        Point(1, 4),
        Point(1, 2),
        Point(1, -2),
        Point(3, 2),
    };

    display(number);
}

int main()
{
    test0();       
    return 0;
}  

第二种方式 – 函数对象

形式

struct ComparePoint
{
	……
}

代码2

在这里插入图片描述

#include <math.h>
#include <iostream>
#include <set>

using std::cout;
using std::endl;
using std::set;

//模板 -- 打印
template <typename Container>    //typename - class 
void display(const Container & con){
    for(auto & elem : con){
        cout << elem << " ";
    }
    cout << endl;
}

class Point
{
public:
    Point(int ix = 0, int iy = 0)
    : _ix(ix)
    , _iy(iy)
    {
    }

    //计算点到原点的距离
    float getDistance() const
    {
        return hypot(_ix, _iy);
    }

    int getX() const
    {
        return _ix;
    }

    int getY() const
    {
        return _iy;
    }

    ~Point()
    {
    }

    friend std::ostream & operator<<(std::ostream & os,const Point & rhs);   //Point
    
    //friend struct ComparePoint;	//好像没将函数对象作为友元,代码运行也可以成功。。。
    								//因为使用了getX() 之类的函数,可以直接访问私有成员

private:
    int _ix;
    int _iy;
};

//由于是自定义模板,需要重载 <<
//同时由于需要访问Point类的私有成员,因此在Point类中需要把该函数声明为友元
std::ostream & operator<<(std::ostream & os,const Point & rhs){
    os << "(" << rhs._ix << "," << rhs._iy << ")";
    return os;
}

//第一种 -- 模板的特化

//第二种 -- 函数对象
struct ComparePoint
{
    //比较2个Point类对象
    bool operator()(const Point &lhs,const Point &rhs) const
    {   
        cout << "struct ComparePoint" << endl;
        // x 和 y均采用升序的方式比较大小
        if(lhs.getX() < rhs.getX())
        {
            return true;
        }else if(lhs.getX() == rhs.getX()){
            if(lhs.getY() < rhs.getY()){
                return true;
            }else{
                return false;
            }
        }
        else    //lhs.getX() > rhs.getX()
        {
            return false;
        }
    } 
};

//第三种 -- 运算符重载



void test0(){
    set<Point,ComparePoint> number = {
        Point(1, 2),
        Point(-1, 2),
        Point(1, 4),
        Point(1, 2),
        Point(1, -2),
        Point(3, 2),
    };

    display(number);
}

int main()
{
    test0();       
    return 0;
}  

第三种方式 – 运算符重载

形式

bool operator<(const Point & lhs,const Point & rhs)
{
	……
}

代码

在这里插入图片描述

#include <math.h>
#include <iostream>
#include <set>

using std::cout;
using std::endl;
using std::set;

//模板 -- 打印
template <typename Container>    //typename - class 
void display(const Container & con){
    for(auto & elem : con){
        cout << elem << " ";
    }
    cout << endl;
}

class Point
{
public:
    Point(int ix = 0, int iy = 0)
    : _ix(ix)
    , _iy(iy)
    {
    }

    //计算点到原点的距离
    float getDistance() const
    {
        return hypot(_ix, _iy);
    }

    int getX() const
    {
        return _ix;
    }

    int getY() const
    {
        return _iy;
    }

    ~Point()
    {
    }

    friend std::ostream & operator<<(std::ostream & os,const Point & rhs);   //Point

    friend bool operator<(const Point &lhs, const Point &rhs);  // < 运算符重载

private:
    int _ix;
    int _iy;
};

//由于是自定义模板,需要重载 <<
//同时由于需要访问Point类的私有成员,因此在Point类中需要把该函数声明为友元
std::ostream & operator<<(std::ostream & os,const Point & rhs){
    os << "(" << rhs._ix << "," << rhs._iy << ")";
    return os;
}

//第一种 -- 模板的特化

//第二种 -- 函数对象

//第三种 -- 运算符重载
bool operator<(const Point & lhs,const Point & rhs){
    cout << "bool operator<" << endl;
    if(lhs.getX() < rhs.getX())
        {
            return true;
        }else if(lhs.getX() == rhs.getX()){
            if(lhs.getY() < rhs.getY()){
                return true;
            }else{
                return false;
            }
        }
        else    //lhs.getX() > rhs.getX()
        {
            return false;
        }
}



void test0(){
    set<Point> number = {
        Point(1, 2),
        Point(-1, 2),
        Point(1, 4),
        Point(1, 2),
        Point(1, -2),
        Point(3, 2),
    };

    display(number);
}

int main()
{
    test0();       
    return 0;
}  

补充

如果模板的特化运算符重载同时存在

优先调用 模板的特化

在这里插入图片描述


完整版代码

//setPoint_three.cc

#include <math.h>
#include <iostream>
#include <set>

using std::cout;
using std::endl;
using std::set;

template <typename Container>
void display(const Container &con)
{
    for(auto &elem : con)
    {
        cout << elem << "  ";
    }
    cout << endl;
}

class Point
{
public:
    Point(int ix = 0, int iy = 0)
    : _ix(ix)
    , _iy(iy)
    {
    }

    //计算点到原点的距离
    float getDistance() const
    {
        return hypot(_ix, _iy);
    }

    int getX() const
    {
        return _ix;
    }

    int getY() const
    {
        return _iy;
    }

    ~Point()
    {
    }

    friend std::ostream &operator<<(std::ostream &os, const Point &rhs);
    friend bool operator<(const Point &lhs, const Point &rhs);
    friend struct ComparePoint;

private:
    int _ix;
    int _iy;
};

std::ostream &operator<<(std::ostream &os, const Point &rhs)
{
    os << "(" << rhs._ix
       << ", " << rhs._iy
       << ")";

    return os;
}

bool operator<(const Point &lhs, const Point &rhs)
{
    cout << "bool operator<" << endl;
    if(lhs.getDistance() < rhs.getDistance())
    {
        return true;
    }
    else if(lhs.getDistance() == rhs.getDistance())
    {
        if(lhs._ix < rhs._ix)
        {
            return true;
        }
        else if(lhs._ix == rhs._ix)
        {
            if(lhs._iy < rhs._iy)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        else
        {
            return false;
        }
    }
    else
    {
        return false;
    }
}

struct ComparePoint
{
    bool operator()(const Point &lhs, const Point  &rhs) const
    {
        cout << "struct ComparePoint" << endl;
        if(lhs.getDistance() < rhs.getDistance())
        {
            return true;
        }
        else if(lhs.getDistance() == rhs.getDistance())
        {
            if(lhs._ix < rhs._ix)
            {
                return true;
            }
            else if(lhs._ix == rhs._ix)
            {
                if(lhs._iy < rhs._iy)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            else
            {
                return false;
            }
        }
        else
        {
            return false;
        }

    }
};

#if 0
namespace std
{
template <class T>
struct less
{
    bool operator()(const T &lhs, const T &rhs) const
    {
        return lhs < rhs;
    }
};
}//end of namespace std
#endif

//命名空间的扩展
namespace  std
{

template <>
struct less<Point>//模板的特化
{
    bool operator()(const Point &lhs, const Point &rhs) const
    {
        cout << "template<> struct less" << endl;
        if(lhs.getDistance() < rhs.getDistance())
        {
            return true;
        }
        else if(lhs.getDistance() == rhs.getDistance())
        {
            if(lhs.getX() < rhs.getX())
            {
                return true;
            }
            else if(lhs.getX() == rhs.getX())
            {
                if(lhs.getY() < rhs.getY())
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            else
            {
                return false;
            }
        }
        else
        {
            return false;
        }
    }
};

}//end of namespace std
 
void test()
{
    set<Point> number = {
    /* set<Point, ComparePoint> number = { */
        Point(1, 2),
        Point(-1, 2),
        Point(1, 4),
        Point(1, 2),
        Point(1, -2),
        Point(3, 2),
    };
    display(number);
}

int main(int argc, char *argv[])
{
    test();
    return 0;
}
ftl文件 <!DOCTYPE html> <html lang="en"> <#include "/common/taglibs.ftl"> <head> <meta charset="UTF-8"> <meta name="apple-mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-status-bar-style" content="black"> <title>农村居住区</title> <link rel="stylesheet" href="${ctx}/plugins/layui/css/layui.css"> <link rel="stylesheet" href="${ctx}/infoSys/css/style.css"> <script src="${ctx}/plugins/jquery-3.3.1.min.js"></script> <script src="${ctx}/plugins/vue/vue.js"></script> <script src="${ctx}/plugins/layui/layui.js"></script> <script src="${ctx}/plugins/common/custom_layui.js"></script> <script src="${ctx}/plugins/nightMap/api.js"></script> <script src="${ctx}/plugins/nightMap/heatmap_min.js"></script> <script src="${ctx}/plugins/nightMap/mapv.js"></script> <script src="${ctx}/plugins/nightMap/haidian.js"></script> <script src="${ctx}/aiplatform/js/verifyList.js"></script> <style> .left-nav-ul .streetManage { border-left: 2px #2080E7 solid; } .left-nav-ul .streetManage a { color: #2080E7; background-image: url(${ctx}/othersSys/images/icon-lajilou2.svg); } .layui-table-box th, .layui-table-box td { text-align: center; } .layui-table-cell { height: auto; line-height: auto; } #addMap { width: 100%; } .administrativeNumber{ width: 100%; height: 50px; line-height: 50px; background-color: #e6f7ff; border: 1px solid #c3e0eb; padding-left: 10px; } </style> </head> <body class="body"> <div class="padding-body" id="app" v-cloak> <iframe src="${ctx}/service/allNav" style="position: fixed;left: 0;top: 0;width: 18rem;height: 100%;" allowfullscreen allow="autoplay; fullscreen"></iframe> <!-- left --> <#-- <#include "/infoSys/nav2.ftl">--> <!-- header --> <#include "/infoSys/header.ftl"> <!-- main --> <section class="main"> <div class="header-title white-bg clearfix"> <h1>{{config.title}}</h1> </div> <div class="main-content white-bg"> <form class="layui-form search-form" onkeypress="return event.keyCode != 13;"> <div class="layui-inline" v-for="(item,index) in config.searchForm"> <label class="layui-form-label first-label">{{item.title}}:</label> <div class="layui-input-inline" v-if="item.type == 'select'"> <select :name="item.prop" :id="item.prop" v-model="searchData[item.prop]" style="width:150px;height:30px" :lay-filter="'form_'+item.prop"> <option v-for="sItem in item.option" :value="sItem.value" >{{sItem.label}}</option> </select> </div> <div class="layui-input-inline" v-else> <input type="text" :id="item.prop" :name="item.prop" v-model="searchData[item.prop]" :placeholder="`请输入`+item.title" autocomplete="off" class="layui-input"/> </div> </div> <#--阻止回车触发提交--> <div class="layui-input-inline" style="width: 200px;display: none;"> <select lay-verify="" type="hidden"> </select> </div> <div class="layui-inline margin-left15" style="float: right;margin-right: 20px;"> <#-- <button type="button" class="layui-btn layui-btn-normal" id="taste_button" lay-submit="record"--> <#-- lay-filter="record">语音--> <#-- </button>--> <#-- <button type="button" class="layui-btn layui-btn-normal" id="start_button" class="start-button"--> <#-- style="display: none">停止--> <#-- </button>--> <button type="button" class="layui-btn layui-btn-normal" lay-submit="" lay-filter="formSearch">查询 </button> <button type="reset" lay-submit lay-filter="formReset" class="layui-btn layui-btn-primary">重置</button> </div> </form> <#-- <div class="administrativeNumber">行政村总数:{{ count }}</div>--> <div> <a class="layui-btn layui-btn-normal layui-btn-sm" v-if="btnJson.add" @click="alertFun('','add')">新建</a> <#-- <a class="layui-btn layui-btn-normal layui-btn-sm" v-if="btnJson.moreUpload" id="moreUpload"--> <#-- class="moreUpload">导入</a>--> <a class="layui-btn layui-btn-normal layui-btn-sm" v-if="btnJson.moreUpload" id="moreUpload" class="moreUpload" @click="uploads">导入</a> <#-- <a class="layui-btn layui-btn-normal layui-btn-sm" v-if="btnJson.download"--> <#-- href="../../../excel/model_street_export.xlsx" download="街镇模板">模板下载</a>--> <a class="layui-btn layui-btn-normal layui-btn-sm" lay-submit="" v-if="btnJson.export" lay-filter="export">导出</a> <#-- <a class="layui-btn layui-btn-normal layui-btn-sm" v-if="btnJson.print" @click="prints()">打印</a>--> <#-- <a class="layui-btn layui-btn-normal layui-btn-sm">新建</a>--> <#-- <a class="layui-btn layui-btn-normal layui-btn-sm" id="moreUpload" class="moreUpload">导入</a>--> <#-- <a class="layui-btn layui-btn-normal layui-btn-sm" href="../../../excel/model_street_export.xlsx" download="街镇模板">模板下载</a>--> <#-- <a class="layui-btn layui-btn-normal layui-btn-sm" lay-submit="" lay-filter="export">导出</a>--> <#-- <a class="layui-btn layui-btn-normal layui-btn-sm" @click="prints()">打印</a>--> </div> <div style="clear:both;"></div> <table id="allTable" lay-filter="allTable" lay-skin="line"></table> </div> </section> <!-- 添加和编辑查看弹窗 --> <form class="layui-form" lay-filter="information" id="information" style="display:none;padding:35px 30px"> <div class="layui-form-item" v-for="(item,index) in config.form"> <div class="layui-inline"> <label class="layui-form-label"><span class="red">*</span> {{item.title}}</label> <div class="layui-input-inline" v-if="item.type == 'select'"> <select :name="item.prop" :id="item.prop" style="width:150px;height:30px"> <option v-for="sItem in item.option" :value="sItem.value">{{sItem.label}}</option> </select> </div> <div class="layui-input-inline" v-else-if="item.type == 'custom-text'"> 自定义内容 </div> <div class="layui-input-inline" v-else> <input type="text" :name="item.prop" autocomplete="off" :lay-verify="item.rule" class="layui-input"/> </div> </div> </div> <div class="layui-form-item"> <div class="layui-input-block"> <button type="button" v-show="type!=='look'" class="layui-btn layui-btn-lg layui-btn-normal" lay-submit="" lay-filter="up">提交 </button> <button type="button" class="layui-btn layui-btn-lg layui-btn-normal" onclick="layer.closeAll()">取消 </button> </div> </div> </form> <div id="UploadFile" class="UploadFileWrapper" style="width: 100%;height: 100%;padding: 1rem;box-sizing: border-box;display: none"> <div class="layui-btn-container" id="upload-btn-warp"> <span id="choiceWrapper"><button type="button" class="layui-btn layui-btn-normal" id="choice">选择文件</button></span> <span id="checkFileWrapper"><button type="button" class="layui-btn" id="checkFile">校验</button></span> <button type="button" class="layui-btn" id="startUpload" @click="fnUploadFile">开始上传</button> </div> <div style="margin: 1rem 0"> <div>操作步骤:</div> <div>1.选择需要上传的文件</div> <div>2.选择完成后击“校验”按钮</div> <div>3.校验通过后击“确认上传”</div> </div> </div> </div> <script> var menusButtonList = '${Session.buttonList?default("")}'; menusButtonList = menusButtonList ? JSON.parse(menusButtonList) : [] $(document).on("keypress", "form", function (event) { return event.keyCode != 13; }) </script> <script src="${ctx}/infoSys/js/public.js"></script> <script src="${ctx}/infoSys/js/countryPlanning/list.js"></script> <script src="${ctx}/infoSys/js/add-map.js"></script> <script src="${ctx}/plugins/rtasr/hmac-sha256.js"></script> <script src="${ctx}/plugins/rtasr/HmacSHA1.js"></script> <script src="${ctx}/plugins/rtasr/md5.js"></script> <script src="${ctx}/plugins/rtasr/enc-base64-min.js"></script> <script src="${ctx}/plugins/rtasr/index.js"></script> <script src="${ctx}/infoSys/js/navPublic.js"></script> </body> </html> js文件 const script = document.createElement('script'); script.src = `${ctx}/infoSys/js/commonJs/formConfig.js`; // 替换为实际的JavaScript文件路径 document.head.appendChild(script); script.onload = function() { // 此处可以执行其他操作 const config = countryPlanningCfg var vues = new Vue({ el: '#app', // mixins: [myMixins], // components:{ // upload // }, watch:{ 'searchData.streetName':function (n,o){ this.loadCommunityData(n) } }, computed:{ config:()=>{ return config } }, data: { navList:[],//nav模块 paramList:{},//nav模块-url tableHead: config.tableHead, streetList: [], communityList: [], menuBtn: [], btnJson: config.btnJson, isHaveHandle: false, searchListFlag: false, searchLi: [], printQuery: '', cheakliat: "", // searchData:{}, name: '', imgShow: false, type: '', url: '', uploadFile: new FormData(), uploadsVar: '', count:0, searchData: { name: '', commName: '', streetName: '', }, }, mounted: function () { // this.getNav() this.menuListBtn() this.table(); this.loadStreetData() // 绑定街道下拉框 change 事件 const streetSelect = document.getElementById('streetName'); if (streetSelect) { streetSelect.addEventListener('change', this.onStreetChange); } layui.use('form', () => { const form = layui.form form.render('select') // 页面加载时初始化所有下拉框 }) const self = this layui.use(['form'], function () { layui.form.on('select(form_streetName)', function (data) { self.searchData.streetName = data.value }) }) // this.selcetInit(); }, methods: { selectChange(prop){ console.log(prop,'prop') }, // 加载街道数据 loadStreetData() { const self = this $.ajax({ url: ctx + '/service/region/list', type: 'GET', data: { grade: 3 // 街道等级为3 }, success: function (res) { console.log(res,'resss') if (res.code === 0) { const streetOptions = res.data.map(item => ({ label: item.name, value: item.coding, coding: item.coding })) console.log('街道数据加载完成:', streetOptions) // 更新街道下拉选项 const streetItem = self.config.searchForm.find(i => i.prop === 'streetName'); if (streetItem) streetItem.option = streetOptions; // 更新搜索表单和编辑表单中的街道下拉选项 self.$set( self.config.searchForm.find(item => item.prop === 'streetName'), 'option', streetOptions ) console.log(self.config.searchForm,'self.config.searchForm') self.$set( self.config.form.find(item => item.prop === 'streetName'), 'option', streetOptions ) self.$forceUpdate() self.$nextTick(() => { setTimeout(() => { layui.form.render('select') }, 100) }) } else { console.error('加载街道数据失败:', res.msg) } }, error: function (xhr, status, error) { console.error('请求失败:', error) } }) }, // 根据街道编码加载社区数据 loadCommunityData(streetCoding) { const self = this; $.ajax({ url: ctx + '/service/region/list', type: 'GET', data: { grade: 4, // 社区等级为4 coding: streetCoding // 传入街道编码 }, success: function (res) { if (res.code === 0) { const commOptions = res.data.map(item => ({ label: item.name, value: item.id })); // 更新社区下拉选项 const commItem = self.config.searchForm.find(i => i.prop === 'commName'); if (commItem) { commItem.option = commOptions; } // 更新搜索表单和编辑表单中的社区下拉选项 const searchCommItem = self.config.searchForm.find(item => item.prop === 'commName'); const formCommItem = self.config.form.find(item => item.prop === 'commName'); if (searchCommItem) { searchCommItem.option.splice(0); // 清空旧数据 searchCommItem.option.push(...commOptions); } if (formCommItem) { formCommItem.option.splice(0); formCommItem.option.push(...commOptions); } self.$forceUpdate() self.$nextTick(() => { layui.form.render('select'); // 重新渲染下拉框 }); } }, error: function (xhr, status, error) { console.error('请求失败:', error); } }); }, // 监听街道选择变化 onStreetChange(event) { console.log('111',event) const streetValue = event.target.value; // 获取选中的街道值 const selectedStreet = this.config.searchForm .find(item => item.prop === 'streetName')?.option .find(item => item.value === streetValue); if (selectedStreet && selectedStreet.coding) { this.loadCommunityData(selectedStreet.coding); // 加载社区数据 } else { // 清空社区下拉框 const communityItem = this.config.searchForm.find(item => item.prop === 'commName'); if (communityItem) communityItem.option = []; const communityFormItem = this.config.form.find(item => item.prop === 'commName'); if (communityFormItem) communityFormItem.option = []; } self.$forceUpdate() this.$nextTick(() => { layui.form.render('select'); // 重新渲染下拉框 }); }, menuListBtn() { this.$nextTick(() => { let arr = [] menusButtonList.forEach((e) => { if (e.menuId == menusIds) { this.menuBtn.push(e) if (e.attrType == 1) { arr.push(e) } } }) console.log(this.menuBtn) this.menuBtn.forEach((e) => { if (e.buttonClass == 'add') { vues.btnJson.add = true } else if (e.buttonClass == 'moreUpload') { vues.btnJson.moreUpload = true } else if (e.buttonClass == 'download') { vues.btnJson.download = true } else if (e.buttonClass == 'export') { vues.btnJson.export = true } else if (e.buttonClass == 'print') { vues.btnJson.print = true } }) if (arr.length == 0) { this.isHaveHandle = true; this.tableHead[0].pop(); } }) }, //显示大图片 showBigImage(e) { layer.open({ type: 1, title: false, closeBtn: 0, shadeClose: true, //击阴影关闭 area: [$(e).width + 'px', $(e).height + 'px'], //宽高 content: "<img src=" + $(e).attr('src') + " />" }); }, //打印 prints() { var v = document.createElement("div"); let self = this; $.ajax({ url: ctx + config.list, data: {limit: 999999, page: 1, ...self.searchData}, success: function (res) { if (res.code == 0) { if (res.data.length) { // <head><link rel="stylesheet" href="'+ctx+'/plugins/layui/css/layui.css"></head> let str = '<html><body><head><style>tr,td{padding:3px}.layui-table {width: 100%;background-color: #fff;color: #666;margin: 10px 0;}.layui-table-cell {height: 28px;line-height: 28px;padding: 0 15px;position: relative;box-sizing: border-box}.layui-table-cell{top: -1px;padding: 0}.layui-table-cell .layui-table-link {color: #01AAED}</style></head><table border style="width: 100%;border-collapse: collapse;border-spacing: 0;" class="layui-table">'; str += '<thead style="background-color: #f2f2f2;width: 100%">'; str += '<tr class=" layui-table-col-special layui-table-cell laytable-cell-1-0-5" style="background-color: #f2f2f2;font-weight: 700">'; config.tableHead[0].forEach(item=>{ str += `<td style="background: #f2f2f2;width: ${item.width}">${item.title}</td>` }) str += '</tr>'; str += '</thead>'; str += '<tbody style="width: 100%">'; for (var i = 0; i < res.data.length; i++) { str += '<tr class="layui-table" >'; config.tableHead[0].forEach(item=>{ if(item.type == 'numbers'){ str += `<td style="width: ${item.width}">${i+1}</td>`; } str += `<td style="background: #f2f2f2;width: ${item.width}">${res.data[i][item.prop] ? res.data[i][item.prop]:'-'}</td>` }) str += '</tr>'; } str += '</tbody>'; str += '</table></body></html>'; var h = window.open("打印窗口", "_blank"); h.document.write(str + $(v).prop("outerHTML")); h.document.close(); console.log(h) h.print(); h.close(); } else { layerObj.failMsg("该条件下暂无数据,无法打印!"); } } ; } }); }, //list table: function () { var self = this; //默认list var dataUrl = ctx + config.url.list; const tableHeadArr = self.tableHead[0].map(item=>{ let templet = null if(item.templet){ templet = item.templet }else if(item.title=='操作'){ templet =function (res){ var btn = ""; btn += '<a target="_blank" class="layui-btn layui-btn-xs" lay-event="look">详情</a >'; return btn; } }else{ templet =function (res) { return !res[item.prop] ? '-' : res[item.prop]; } } return { ...item, templet:templet } }) layerObj.tableList([tableHeadArr], 'allTable', dataUrl, 'tool(allTable)', function (res, curr, count) { self.count = count }, function (e) { let id = e.data.id; //查看 if (e.event === "look") { self.alertFun(id, 'look',e.data) } //编辑 if (e.event === "edit") { self.alertFun(id, 'edit') } // 删除 if (e.event === 'delete') { layer.confirm('是否删除?', { btn: ['确定', '取消'] //可以无限个按钮 }, function (index, layero) { layerObj.ajaxSend( 'get', ctx + `${config.url.delete}?id=` + id, 'json', {}, function (data) { if (data.code === 1) { layer.alert(data.msg); } else { self.table(); } } ); layer.close(index); }, function (index) { layer.close(index); }); } }, "allTable"); //搜索 layui.use(['form', 'table', 'upload'], function () { var form = layui.form; var table = layui.table; var upload = layui.upload; form.on("submit(formSearch)", function (data) { table.reload("allTable", { headers: self.tableHead, url: dataUrl, page: {curr: 1}, where: data.field, done: function () { } }, 'data'); }); // 重置 form.on("submit(formReset)", function (data) { self.condition = null table.reload("allTable", { headers: self.tableHead, url: dataUrl, page: {curr: 1}, where: self.condition, done: function () { } }, 'data'); }); //导出 form.on("submit(export)", function (data) { var name = $('input[name="name"]').val(); var cs = ctx + `${config.url.export}?name=` + name; window.open(cs); }); //上传附件 var uploadInst = upload.render({ elem: '#uploadBtn' , url: ctx + '/service/upload/minio/uploadAttach' , accept: 'file' //普通文件 , choose: function (obj) { obj.preview(function (index, file, result) { self.fileName = file.name; $('#attachUrl').html(file.name); }) } , done: function (res) { if (res.code > 0) { self.filePath = res.data.filePath self.imgShow = true $('#attachUrl').on('click', function () { window.location.href = ctx + '/service/upload/minio/downloadReplaceFileName?filename=' + $('#attachUrl').text() + '&fileUrlName=' + res.data.fileName }) layer.msg('上传成功'); }else { layer.msg(res.msg); } } }); }); }, //添加和编辑弹窗 alertFun(myid, type,data) { var self = this; self.type = type document.getElementById("information").reset(); self.imgShow = false $('#image').val(""); $("#roleIds,#roleNames").val(""); var titleName; var postUrl = ''; if (type == 'edit') { titleName = "编辑"; postUrl = ctx + config.url.edit } else if (type == 'add'){ titleName = "新建"; postUrl = ctx + config.url.add }else{ titleName = "查看"; } $('#imageWrapper').html('<input type="hidden" name="image" id="image" />') layui.use(['form', 'layer', 'upload', 'laydate'], function () { let form = layui.form; let layer = layui.layer; let upload = layui.upload; let laydate = layui.laydate; var myLayer = layer.open({ title: titleName + "菜单", type: 1, area: ["900px", "700px"], content: $("#information"), success: function () { if (myid && config.url.detail) { //回显 $.ajax({ url: ctx + `${config.url.detail}?id=` + myid, success: function (res) { const obj = {} config.form.forEach((item,index)=>{ obj[item.prop] = res.data[item.prop] ? res.data[item.prop] : '' }) form.val("information",obj); //文件 var image = res.data.image; self.filePath = image if (image && image != "") { self.imgShow = image ? true : false; $('#attachUrl').html(image.split('_')[image.split('_').length - 1]); $('#attachUrl').on('click', function () { window.location.href = ctx + '/service/upload/minio/downloadReplaceFileName?filename=' + $('#attachUrl').text() + '&fileUrlName=' + image }) } self.$nextTick(() => { form.render() }) } }); }else if(!config.url.detail){ const obj = {} config.form.forEach((item,index)=>{ obj[item.prop] = data[item.prop] ? data[item.prop] : '' }) form.val("information",obj); } else { form.val("information", {}); $('#attachUrl').html(''); self.imgShow = false; self.$nextTick(() => { form.render() }) } form.on('submit(up)', function (data) { let paramObj = data.field; paramObj.pid = self.pid; paramObj.imageUrl = self.filePath; if (myid) { paramObj.id = myid; } layerObj.commonAjax('POST', postUrl, "json", paramObj, function (data) { if (data.code == 0) { layer.closeAll(); layerObj.successMsg("保存成功!"); self.table(); } else { layerObj.failMsg(data.msg); } }); }); // 校验 form.verify(config.formVerify) } }); }); }, //击搜索列表 queryBtn: function () { var self = this; self.searchListFlag = true; $.ajax({ url: ctx + '/service/baiduMap/get/suggestion', type: 'post', data: { "keyword": self.printQuery, "region": "北京市", "pageSize": 20, "pageNum": 1 }, success: function (res) { if (res.data.results) { self.searchLi = res.data.results; } } }); }, //确认选择li chooseLi: function (item) { var self = this; self.searchListFlag = false; var lng = item.location.longitude, lat = item.location.latitude; addPointFun(lng, lat); $(".longitudeLatitude").val(lng + "," + lat); $(".longitude").val(lng); $(".latitude").val(lat); self.printQuery = item.address; $(".detailAddress").val(item.address); bm.centerAndZoom(new BMap.Point(lng, lat), 14); }, // 页面初始化 pageInit() { var self = this; layui.use(['form', 'upload', 'layer'], function () { var upload = layui.upload; self.uploadsVar = upload.render({ elem: '#choice', accept: 'file', acceptMime: 'application/vnd.ms-excel, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', exts: 'xlsx|xls', //只允许上传excel文件, auto: false, bindAction: '#checkFile' }); }) }, // 上传弹框 uploads() { $('#choiceWrapper').html('<button type="button" class="layui-btn layui-btn-normal" id="choice">选择文件</button>'); this.uploadsVar = ''; $('.layui-upload-choose').html(''); $('#checkFileWrapper').html('<span id="checkFileWrapper"><button type="button" class="layui-btn" id="checkFile">校验</button></span>'); this.pageInit() this.$nextTick(() => { $('#startUpload').css('display', 'none') }) let self = this layui.use(['form', 'upload', 'layer'], function () { let form = layui.form; let layer = layui.layer; var upload = layui.upload; var checkurl = '' var myLayer = layer.open({ title: '上传文件', type: 1, area: ["680px", "250px"], content: $("#UploadFile"), success: function (res) { // 校验接口 checkurl = ctx + '/service/base/street/checkExcelUpload' self.uploadsVar.reload({ elem: '#choice', accept: 'file', acceptMime: 'application/vnd.ms-excel, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', exts: 'xlsx|xls', //只允许上传excel文件, url: checkurl, auto: false, bindAction: '#checkFile', choose: (obj) => { $('#startUpload').css('display', 'none') self.uploadFile = new FormData(); var files = obj.pushFile(); var firstProp; var count = 0; // 获取第一个属性 for (var key in files) { if (files.hasOwnProperty(key)) { firstProp = key; break; } } // 统计文件数 for (var k in files) { count++; } if (count > 1) { delete files[firstProp]; } //预读本地文件,如果是多文件,则会遍历。(不支持ie8/9) obj.preview(function (index, file, result) { self.uploadFile.append('file', file); }); }, done: function (res, index) { if (res.code == 0) { layer.msg(res.msg); $('#startUpload').css('display', 'inline-block') } else { layer.alert(res.msg); $('#startUpload').css('display', 'none') } } }); } , end: () => { $('#startUpload').css('display', 'none') } }) }) }, // 上传 fnUploadFile() { var self = this layui.use(['layer'], function () { var layer = layui.layer; // 上传接口 var url = '' url = ctx + config.url.import let key = self.uploadFile.getAll('file')[0]; $.ajax({ url: url, method: 'post', data: self.uploadFile, contentType: false, processData: false, dataType: "json", async: false, success: (res) => { if (res.code == 0) { layer.msg(res.msg); setTimeout(() => { layer.closeAll(); self.table(); }, 2500); } else { layer.alert(res.msg); } }, fail: (res) => { layer.alert(res.msg); } }) }) }, //nav-获取列表 getNav(){ let self = this let url = document.location.toString() let urlObj = url.split('?') let paramObj let paramList = {}//url参数集合 if(urlObj.length >0){ paramObj = urlObj[1].split('&') paramObj.forEach((val,index)=>{ let arrList = val.split('=') Object.defineProperty(paramList,arrList[0],{value:arrList[1]}) // paramList.arrList[0] = arrList[1] }) } self.paramList = paramList //获取菜单列表并渲染 $.ajax({ url:ctx + "/service/authorityMenu/listByMenuId?menuId="+paramList.pid, type:"get", success:function (res) { console.log('菜单请求返回值',res) if(res.code == 0){ //修改数据内容 渲染nav选中项 res.data.forEach((val,index)=>{ if(val.childMenus.length>0){ val.childMenus.forEach((value)=>{ value.select = false; if(value.id == self.paramList.cid||value.id == self.paramList.cPid){ value.select = true; } value.childMenus }) } }) self.navList = res.data } } }) }, //nav-页面跳转 toUrl(items){ console.log(items) if(items.url.indexOf('?') != -1){ window.location.href = ctx + items.url+'&pid='+this.paramList.pid+'&cid='+items.id+'&cPid='+items.pid }else{ window.location.href = ctx + items.url+'?pid='+this.paramList.pid+'&cid='+items.id+'&cPid='+items.pid } }, //nav-渲染nav选中项 changeNavState(items){ items.select = !items.select }, //时间戳转日期函数 DateFormat(sjc) { var date = new Date(sjc); var y = date.getFullYear(); var m = date.getMonth() + 1; m = m < 10 ? '0' + m : m; var d = date.getDate(); d = d < 10 ? ("0" + d) : d; var h = date.getHours(); h = h < 10 ? ("0" + h) : h; var min = date.getMinutes(); min = min < 10 ? ("0" + min) : min; var s = date.getSeconds(); s = s < 10 ? ("0" + s) : s; var str = y + "-" + m + "-" + d + " " + h + ":" + min + ":" + s; return str; }, }, }) }; 击街镇和社区下拉选择后进行查询选择的数据
最新发布
09-04
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值