2 Angajamente 28e42242d5 ... 28e43c4f8c

Autor SHA1 Permisiunea de a trimite mesaje. Dacă este dezactivată, utilizatorul nu va putea trimite nici un fel de mesaj Data
  YueYunyun 28e43c4f8c update 不更新虚拟区域到真实邮箱的区域上,方便以后区域调整的维护 11 luni în urmă
  YueYunyun e02dae5818 Add 增加提取招标信息的预算金额功能 11 luni în urmă

+ 2 - 1
SourceCode/TenderCrawler/README.md

@@ -115,8 +115,9 @@ email:
   smtp_password: 'password' # SMTP密码
   from_email: 'from@example.com' # 发件人地址
   error_email: 'error@example.com' # 错误通知邮箱
+  default_email: 'default@example.com' # 默认收件人地址,所有业务邮件都发送到该地址
 
-# 数据库配置
+# 数据库配置  可以在docker-compose中的环境变量中配置
 mysql:
   host: 'localhost' # 数据库主机
   port: 3306 # 数据库端口

+ 2 - 0
SourceCode/TenderCrawler/app/config.yml

@@ -49,6 +49,7 @@ ai:
     city: string; // 招标单位城市
     date: string; // 项目开标的时间
     address: string; // 项目开标的地点
+    budget: string; // 项目预算金额,单位换成元,没有留空
     release_date: string; // 招标信息的发布时间
     summary: string; // 100字左右的招标条件,联系方式等内容摘要
     devices: string; // 只涉及到光谱仪相关的设备,其他无关设备不需要,多个设备以逗号分割 ,例如 红外光谱仪,拉曼光谱仪等
@@ -86,6 +87,7 @@ email:
   smtp_password: FWRwBZKHTLHjHT5F
   from_email: yueyunyun88@163.com
   error_email:
+  default_email: 349977741@qq.com
 job:
   event_id: 1 # 改变这个值,整点会检测重新加载任务
   sleep_interval: 10

+ 33 - 20
SourceCode/TenderCrawler/app/jobs/data_process.py

@@ -19,6 +19,7 @@ class DataProcess:
                 city: string; // 招标单位城市
                 date: string; // 项目开标的时间
                 address: string; // 项目开标的地点
+                budget: string; // 项目预算金额,单位换成元,没有留空
                 release_date: string; // 招标信息的发布时间
                 summary: string; // 100字左右的招标条件,联系方式等内容摘要
                 devices: string; // 只涉及到光谱仪相关的设备,其他无关设备不需要,多个设备以逗号分割 ,例如 红外光谱仪,拉曼光谱仪等
@@ -50,11 +51,14 @@ class DataProcess:
     def __init__(self, store: IDataStore):
         self._store = store
         self._ai_system_prompt = utils.get_config_value(
-            "ai.system_prompt", self.DEFAULT_AI_SYSTEM_PROMPT)
+            "ai.system_prompt", self.DEFAULT_AI_SYSTEM_PROMPT
+        )
         self._ai_prompt_template_1 = utils.get_config_value(
-            "ai.prompt_template_1", self.DEFAULT_AI_PROMPT_TEMPLATE_1)
+            "ai.prompt_template_1", self.DEFAULT_AI_PROMPT_TEMPLATE_1
+        )
         self._ai_prompt_template_2 = utils.get_config_value(
-            "ai.prompt_template_2", self.DEFAULT_AI_PROMPT_TEMPLATE_2)
+            "ai.prompt_template_2", self.DEFAULT_AI_PROMPT_TEMPLATE_2
+        )
 
     @property
     def store(self) -> IDataStore:
@@ -81,20 +85,27 @@ class DataProcess:
             if item.status == 1:
                 utils.get_logger().info(f"ALREADY1 URL:{url}")
                 return
-            data = (self.store.query_one_process_by_url(url) if item.data_type
-                    == 0 else self.store.query_one_process_result_by_url(url))
+            data = (
+                self.store.query_one_process_by_url(url)
+                if item.data_type == 0
+                else self.store.query_one_process_result_by_url(url)
+            )
             if data:
-                utils.get_logger().info(
-                    f"ALREADY2 [{item.data_type}] URL==> {url}")
+                utils.get_logger().info(f"ALREADY2 [{item.data_type}] URL==> {url}")
                 return
-            data = (self._ai_process_1(item)
-                    if item.data_type == 0 else self._ai_process_2(item))
+            data = (
+                self._ai_process_1(item)
+                if item.data_type == 0
+                else self._ai_process_2(item)
+            )
             if data:
                 old = None
                 if data.no:
-                    old = (self.store.query_one_process_result_by_no(data.no)
-                           if item.data_type == 0 else
-                           self.store.query_one_process_by_no(data.no))
+                    old = (
+                        self.store.query_one_process_result_by_no(data.no)
+                        if item.data_type == 0
+                        else self.store.query_one_process_by_no(data.no)
+                    )
                 if not old:
                     data.url = url
                     data.keyword = item.keyword
@@ -110,14 +121,15 @@ class DataProcess:
                         else:
                             old.other_urls = url
                         if item.data_type == 0:
-                            self.store.set_process_other_urls(
-                                data.url, old.other_urls)
+                            self.store.set_process_other_urls(data.url, old.other_urls)
                         else:
                             self.store.set_process_result_other_urls(
-                                data.url, old.other_urls)
+                                data.url, old.other_urls
+                            )
                     self.store.set_collect_process(old.url)
                     utils.get_logger().info(
-                        f"ALREADY 编号: {data.no} URL:{old.other_urls}")
+                        f"ALREADY 编号: {data.no} URL:{old.other_urls}"
+                    )
 
             utils.get_logger().info("END   ==>" + url)
         except Exception as e:
@@ -126,8 +138,8 @@ class DataProcess:
     def _ai_process_1(self, item: CollectData) -> ProcessData | None:
         try:
             data = utils.call_openai(
-                self._ai_system_prompt,
-                f"{item.content} {self._ai_prompt_template_1}")
+                self._ai_system_prompt, f"{item.content} {self._ai_prompt_template_1}"
+            )
             # area_str = data.get("area")
             #
             # if "省" in area_str:
@@ -145,6 +157,7 @@ class DataProcess:
                 city=data.get("city"),
                 address=data.get("address"),
                 devices=data.get("devices"),
+                budget=data.get("budget"),
                 summary=data.get("summary"),
                 release_date=data.get("release_date"),
                 prompt_tokens=data.get("prompt_tokens"),
@@ -158,8 +171,8 @@ class DataProcess:
     def _ai_process_2(self, item: CollectData) -> ProcessResultData | None:
         try:
             data = utils.call_openai(
-                self._ai_system_prompt,
-                f"{item.content} {self._ai_prompt_template_2}")
+                self._ai_system_prompt, f"{item.content} {self._ai_prompt_template_2}"
+            )
             result = ProcessResultData(
                 no=data.get("no"),
                 title=data.get("title"),

+ 17 - 18
SourceCode/TenderCrawler/app/jobs/data_send.py

@@ -17,6 +17,7 @@ class DataSend:
         return self._store
 
     def __init__(self, store: IDataStore):
+        self._default_email = utils.get_config_value("email.default_email", "")
         self._store = store
         self._email_area_arr = self.store.query_all_emails()
         self._email_area_virtual_arr = self.store.query_all_virtual_emails()
@@ -45,6 +46,8 @@ class DataSend:
             f"开始发送中标报告邮件,开始日期:{start_date.strftime("%Y-%m-%d")},结束日期:{end_date.strftime("%Y-%m-%d")}"
         )
         email = self.store.query_master_email()
+        if self._default_email and self._default_email not in email:
+            email = email + "," + self._default_email if email else self._default_email
         if not email:
             utils.get_logger().error("没有找到master email")
             return
@@ -61,21 +64,23 @@ class DataSend:
         utils.get_logger().info(f"开始发送邮件,地区为:{item.city} ,URL为 {item.url}")
         email = self._get_email_by_area(item.city)
         if not email:
+            email = ""
             utils.get_logger().error(f"{item.city} 下没有找到email")
             if item.city not in self._error_arr:
                 self._error_arr.append(item.city)
-            return
-        title_prev = utils.get_config_value("email.title_prev", "【招标信息】")
-        body = self._build_email_html(item)
-        flag = utils.send_email(
-            email, f"{title_prev} {item.title}", body, True, item.attach_path
-        )
+        if self._default_email and self._default_email not in email:
+            email = email + "," + self._default_email if email else self._default_email
+        flag = False
+        if item.title:
+            title_prev = utils.get_config_value("email.title_prev", "【招标信息】")
+            body = self._build_email_html(item)
+            flag = utils.send_email(
+                email, f"{title_prev} {item.title}", body, True, item.attach_path
+            )
         if flag:
             self.store.set_send(item.no)
 
-    def _get_email_by_area(
-        self, area: str, count: int = 0, virtual_area: str = None
-    ) -> str:
+    def _get_email_by_area(self, area: str, count: int = 0) -> str:
         email = None
         area_str = (
             area.replace("省", "").replace("市", "").replace("区", "").replace("县", "")
@@ -83,18 +88,11 @@ class DataSend:
         for area_item in self._email_area_arr:
             if area_str in area_item.area:
                 email = area_item.email
-                if virtual_area:
-                    new_area = f"{area_item.area},{virtual_area}"
-                    self.store.update_area_email_area_by_name(area_item.name, new_area)
-                    self._email_area_arr = self.store.query_all_emails()
                 break
-        if not email and count < 3:
+        if not email and count <= 3:
             area_name = self._get_email_by_area_virtual(area_str)
             if area_name:
-                virtual_area = (
-                    f"{area_str},{virtual_area}" if virtual_area else area_str
-                )
-                email = self._get_email_by_area(area_name, count + 1, virtual_area)
+                email = self._get_email_by_area(area_name, count + 1)
         return email
 
     def _get_email_by_area_virtual(self, area: str) -> str:
@@ -157,6 +155,7 @@ class DataSend:
                 <h1>{item.title}</h1>
                 <p><strong>招标编号:</strong> {item.no if item.no else ""}</p>
                 <p><strong>项目区域:</strong> {item.province if item.province else ""}{item.city if item.city else ""}</p>
+                {f"<p><strong>项目预算:</strong> {item.budget + "元"}</p>" if item.budget else ""}
                 <p><strong>相关设备:</strong> {item.devices if item.devices else ""}</p>
                 <p><strong>开标时间:</strong> {item.date if item.date else ""}</p>
                 <p><strong>开标地点:</strong> {item.address if item.address else ""}</p>

+ 44 - 33
SourceCode/TenderCrawler/app/models/process_data.py

@@ -16,6 +16,7 @@ class ProcessData:
         province=None,
         city=None,
         address=None,
+        budget=None,
         summary=None,
         release_date=None,
         devices=None,
@@ -33,13 +34,14 @@ class ProcessData:
         self.title = title
         self.url = url
         self.date = date
-        self.province = province.replace("省", "").replace(
-            "市", "") if province else ""
-        self.city = (city.replace("市", "").replace("区", "").replace("县", "")
-                     if city else "")
+        self.province = province.replace("省", "").replace("市", "") if province else ""
+        self.city = (
+            city.replace("市", "").replace("区", "").replace("县", "") if city else ""
+        )
         if self.province == self.city:
             self.province = ""
         self.keyword = keyword
+        self.budget = budget
         self.address = address
         self.summary = summary
         self.release_date = release_date
@@ -59,11 +61,12 @@ class ProcessData:
             f"ProcessData(no={self.no}, title={self.title}, date={self.date}, "
             f"province={self.province},city={self.city}, address={self.address}, summary={self.summary}, "
             f"status={self.status}, create_time={self.create_time}, "
-            f"send_time={self.send_time}, remark={self.remark})")
+            f"send_time={self.send_time}, remark={self.remark})"
+        )
 
     _insert_query = """
-              INSERT IGNORE INTO t_data (no, title, url, keyword, date, province, city, address, summary, release_date, devices, attach_path, status, create_time, prompt_tokens, completion_tokens, total_tokens)
-              VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s);
+              INSERT IGNORE INTO t_data (no, title, url, keyword, date, province, city, address, budget, summary, release_date, devices, attach_path, status, create_time, prompt_tokens, completion_tokens, total_tokens)
+              VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s);
           """
 
     # _update_query = """
@@ -82,6 +85,7 @@ class ProcessData:
             process_data.province,
             process_data.city,
             process_data.address,
+            process_data.budget,
             process_data.summary,
             process_data.release_date,
             process_data.devices,
@@ -102,29 +106,34 @@ class ProcessData:
 
     def insert_batch(self, process_data_list):
         if not all(
-                isinstance(process_data, self.__class__)
-                for process_data in process_data_list):
+            isinstance(process_data, self.__class__)
+            for process_data in process_data_list
+        ):
             raise TypeError("process_data_list 中的所有元素必须是 ProcessData 的实例")
 
-        insert_params = [(
-            process_data.no,
-            process_data.title,
-            process_data.url,
-            process_data.keyword,
-            process_data.date,
-            process_data.province,
-            process_data.city,
-            process_data.address,
-            process_data.summary,
-            process_data.release_date,
-            process_data.devices,
-            process_data.attach_path,
-            0,
-            datetime.now(),
-            process_data.prompt_tokens,
-            process_data.completion_tokens,
-            process_data.total_tokens,
-        ) for process_data in process_data_list]
+        insert_params = [
+            (
+                process_data.no,
+                process_data.title,
+                process_data.url,
+                process_data.keyword,
+                process_data.date,
+                process_data.province,
+                process_data.city,
+                process_data.address,
+                process_data.budget,
+                process_data.summary,
+                process_data.release_date,
+                process_data.devices,
+                process_data.attach_path,
+                0,
+                datetime.now(),
+                process_data.prompt_tokens,
+                process_data.completion_tokens,
+                process_data.total_tokens,
+            )
+            for process_data in process_data_list
+        ]
 
         # update_params = [(process_data.url, )
         #                  for process_data in process_data_list]
@@ -143,7 +152,7 @@ class ProcessData:
 
     def fetch_one_process_by_url(self, url: str):
         with MySQLHelper() as db_helper:
-            result = db_helper.fetch_one(self._one_url_query, (url, ))
+            result = db_helper.fetch_one(self._one_url_query, (url,))
             if not result:
                 return None
             data = ProcessData(
@@ -161,7 +170,7 @@ class ProcessData:
     def fetch_one_process_by_no(self, no: str):
         with MySQLHelper() as db_helper:
 
-            result = db_helper.fetch_one(self._one_no_query, (no, ))
+            result = db_helper.fetch_one(self._one_no_query, (no,))
             if not result:
                 return None
             data = ProcessData(
@@ -172,7 +181,7 @@ class ProcessData:
             )
             return data
 
-    _not_send_query = "SELECT no, title, url, keyword, devices,date, city, address, summary, attach_path, release_date FROM t_data WHERE status = 0"
+    _not_send_query = "SELECT no, title, url, keyword, devices,date, city, address, budget, summary, attach_path, release_date FROM t_data WHERE status = 0"
 
     def fetch_not_send(self):
         with MySQLHelper() as db_helper:
@@ -204,8 +213,10 @@ class ProcessData:
         :return: 删除的行数
         """
         with MySQLHelper() as db_helper:
-            params = (date, )
+            params = (date,)
             db_helper.execute_non_query(self._delete_before_date_query, params)
             affected_rows = db_helper.connection.affected_rows()
-            utils.get_logger().info(f"删除 {date} 之前共 {affected_rows} 条 招标处理记录。")
+            utils.get_logger().info(
+                f"删除 {date} 之前共 {affected_rows} 条 招标处理记录。"
+            )
             return affected_rows

+ 1 - 1
SourceCode/TenderCrawler/docker-compose.yml

@@ -56,7 +56,7 @@ services:
       #      - APP_AI__KEY=
       #      - APP_AI__URL=http://192.168.0.109:7580/api/chat
       #      - APP_AI__MODEL=qwen2.5:7b
-      - APP_LOGGER__LEVEL=INFO
+      - APP_LOGGER__LEVEL=DEBUG
       - APP_JOB__COLLECT=20:00,12:00
       - APP_JOB__PROCESS=23:00,4:00,13:00
       - APP_JOB__SEND_EMAIL=08:20,14:00

+ 15 - 10
SourceCode/TenderCrawler/init.sql

@@ -38,11 +38,11 @@ CREATE TABLE `t_area_email`  (
   PRIMARY KEY (`name`) USING BTREE
 ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin ROW_FORMAT = Dynamic;
 
-INSERT INTO `t_area_email` (`name`, `area`, `email`, `is_virtual`, `is_active`, `remark`) VALUES ('master', 'master', 'chancelot@foxmail.com,349977741@qq.com', 0,1, NULL);
-INSERT INTO `t_area_email` (`name`, `area`, `email`, `is_virtual`, `is_active`, `remark`) VALUES ('all', '全国', 'chancelot@foxmail.com,349977741@qq.com', 0,1, NULL);
+INSERT INTO `t_area_email` (`name`, `area`, `email`, `is_virtual`, `is_active`, `remark`) VALUES ('master', 'master', '349977741@qq.com', 0,1, NULL);
+INSERT INTO `t_area_email` (`name`, `area`, `email`, `is_virtual`, `is_active`, `remark`) VALUES ('all', '全国', '349977741@qq.com', 0,1, NULL);
 INSERT INTO `t_area_email` (`name`, `area`, `email`, `is_virtual`, `is_active`, `remark`) VALUES ('张志琼', '黑龙江,吉林,辽宁', 'zhiqiong.zhang@bruker.com', 0,0, NULL);
-INSERT INTO `t_area_email` (`name`, `area`, `email`, `is_virtual`, `is_active`, `remark`) VALUES ('王双', '河北,济南,山东德州', 'shuang.wang@bruker.com', 0,0, NULL);
-INSERT INTO `t_area_email` (`name`, `area`, `email`, `is_virtual`, `is_active`, `remark`) VALUES ('范国春', '山东', 'guochun.fan@bruker.com', 0,0, NULL);
+INSERT INTO `t_area_email` (`name`, `area`, `email`, `is_virtual`, `is_active`, `remark`) VALUES ('王双', '河北,山东_02', 'shuang.wang@bruker.com', 0,0, NULL);
+INSERT INTO `t_area_email` (`name`, `area`, `email`, `is_virtual`, `is_active`, `remark`) VALUES ('范国春', '山东_01', 'guochun.fan@bruker.com', 0,0, NULL);
 INSERT INTO `t_area_email` (`name`, `area`, `email`, `is_virtual`, `is_active`, `remark`) VALUES ('尚祖俭', '天津', 'zujian.shang@bruker.com', 0,0, NULL);
 INSERT INTO `t_area_email` (`name`, `area`, `email`, `is_virtual`, `is_active`, `remark`) VALUES ('赵跃', '北京', 'yue.zhao@bruker.com', 0,0, NULL);
 INSERT INTO `t_area_email` (`name`, `area`, `email`, `is_virtual`, `is_active`, `remark`) VALUES ('张景灿', '陕西,新疆,宁夏,青海', 'jingcan.zhang@bruker.com', 0,0, NULL);
@@ -54,10 +54,10 @@ INSERT INTO `t_area_email` (`name`, `area`, `email`, `is_virtual`, `is_active`,
 INSERT INTO `t_area_email` (`name`, `area`, `email`, `is_virtual`, `is_active`, `remark`) VALUES ('邬歆', '安徽,香港,澳门', 'xin.wu@bruker.com', 0,0, NULL);
 INSERT INTO `t_area_email` (`name`, `area`, `email`, `is_virtual`, `is_active`, `remark`) VALUES ('冯新宝', '湖北,湖南', 'xinbao.feng@bruker.com', 0,0, NULL);
 INSERT INTO `t_area_email` (`name`, `area`, `email`, `is_virtual`, `is_active`, `remark`) VALUES ('耿朝曦', '江西,贵州', 'zhaoxi.geng@bruker.com', 0,0, NULL);
-INSERT INTO `t_area_email` (`name`, `area`, `email`, `is_virtual`, `is_active`, `remark`) VALUES ('李华斌', '广西,深圳', 'huabin.li@bruker.com', 0,0, NULL);
-INSERT INTO `t_area_email` (`name`, `area`, `email`, `is_virtual`, `is_active`, `remark`) VALUES ('吕万明', '海南,广州,中山', 'wanming.lv@bruker.com', 0,0, NULL);
-INSERT INTO `t_area_email` (`name`, `area`, `email`, `is_virtual`, `is_active`, `remark`) VALUES ('许建光', '西藏,云南,广东', 'jianguang.xu@bruker.com', 0,0, NULL);
-INSERT INTO `t_area_email` (`name`, `area`, `email`, `is_virtual`, `is_active`, `remark`) VALUES ('全国', '北京,天津,上海,重庆,河北,山西,黑龙江,吉林,辽宁,江苏,浙江,安徽,福建,江西,山东,河南,湖北,湖南,广东,海南,四川,贵州,云南,陕西,甘肃,青海,台湾,内蒙古,广西,西藏,宁夏,新疆,香港,澳门', '', 1, 1, NULL);
+INSERT INTO `t_area_email` (`name`, `area`, `email`, `is_virtual`, `is_active`, `remark`) VALUES ('许建光', '西藏,云南,广东_01', 'jianguang.xu@bruker.com', 0,0, NULL);
+INSERT INTO `t_area_email` (`name`, `area`, `email`, `is_virtual`, `is_active`, `remark`) VALUES ('李华斌', '广西,广东_02', 'huabin.li@bruker.com', 0,0, NULL);
+INSERT INTO `t_area_email` (`name`, `area`, `email`, `is_virtual`, `is_active`, `remark`) VALUES ('吕万明', '海南,广东_03', 'wanming.lv@bruker.com', 0,0, NULL);
+INSERT INTO `t_area_email` (`name`, `area`, `email`, `is_virtual`, `is_active`, `remark`) VALUES ('全国', '北京,天津,上海,重庆,河北,山西,黑龙江,吉林,辽宁,江苏,浙江,安徽,福建,江西,山东_01,山东_02,河南,湖北,湖南,广东_01,广东_02,广东_03,海南,四川,贵州,云南,陕西,甘肃,青海,台湾,内蒙古,广西,西藏,宁夏,新疆,香港,澳门', '', 1, 1, NULL);
 INSERT INTO `t_area_email` (`name`, `area`, `email`, `is_virtual`, `is_active`, `remark`) VALUES ('北京', '东城区,西城区,朝阳区,丰台区,石景山区,海淀区,门头沟区,房山区,通州区,顺义区,大兴区,昌平区,平谷区,怀柔区,密云区,延庆区', '', 1, 1, NULL);
 INSERT INTO `t_area_email` (`name`, `area`, `email`, `is_virtual`, `is_active`, `remark`) VALUES ('上海', '黄浦区,徐汇区,长宁区,静安区,普陀区,虹口区,杨浦区,宝山区,闵行区,嘉定区,浦东新区,金山区,松江区,青浦区,奉贤区,崇明区', '', 1, 1, NULL);
 INSERT INTO `t_area_email` (`name`, `area`, `email`, `is_virtual`, `is_active`, `remark`) VALUES ('天津', '和平区,河东区,河西区,南开区,河北区,红桥区,东丽区,西青区,北辰区,武清区,宝坻区,滨海新区,宁河区,静海区,蓟州区', '', 1, 1, NULL);
@@ -74,7 +74,8 @@ INSERT INTO `t_area_email` (`name`, `area`, `email`, `is_virtual`, `is_active`,
 INSERT INTO `t_area_email` (`name`, `area`, `email`, `is_virtual`, `is_active`, `remark`) VALUES ('河北', '石家庄,唐山,秦皇岛,邯郸,邢台,保定,张家口,承德,沧州,廊坊,衡水', '', 1, 1, NULL);
 INSERT INTO `t_area_email` (`name`, `area`, `email`, `is_virtual`, `is_active`, `remark`) VALUES ('河南', '郑州,开封,洛阳,平顶山,安阳,鹤壁,新乡,焦作,濮阳,许昌,漯河,三门峡,南阳,商丘,周口,驻马店,济源示范区', '', 1, 1, NULL);
 INSERT INTO `t_area_email` (`name`, `area`, `email`, `is_virtual`, `is_active`, `remark`) VALUES ('甘肃', '兰州,嘉峪关,金昌,白银,天水,武威,张掖,平凉,酒泉,庆阳,定西,陇南,临夏回族自治州,甘南藏族自治州', '', 1, 1, NULL);
-INSERT INTO `t_area_email` (`name`, `area`, `email`, `is_virtual`, `is_active`, `remark`) VALUES ('山东', '青岛,淄博,枣庄,东营,烟台,潍坊,济宁,泰安,威海,日照,莱州,临沂,聊城,滨州,菏泽', '', 1, 1, NULL);
+INSERT INTO `t_area_email` (`name`, `area`, `email`, `is_virtual`, `is_active`, `remark`) VALUES ('山东_01', '青岛,淄博,枣庄,东营,烟台,潍坊,济宁,泰安,威海,日照,莱州,临沂,聊城,滨州,菏泽', '', 1, 1, NULL);
+INSERT INTO `t_area_email` (`name`, `area`, `email`, `is_virtual`, `is_active`, `remark`) VALUES ('山东_02', '济南,德州', '', 1, 1, NULL);
 INSERT INTO `t_area_email` (`name`, `area`, `email`, `is_virtual`, `is_active`, `remark`) VALUES ('内蒙古', '呼和浩特,包头,乌海,赤峰,通辽,鄂尔多斯,呼伦贝尔,巴彦淖尔,乌兰察布,兴安盟,锡林郭勒盟,阿拉善盟', '', 1, 1, NULL);
 INSERT INTO `t_area_email` (`name`, `area`, `email`, `is_virtual`, `is_active`, `remark`) VALUES ('浙江', '杭州,宁波,温州,嘉兴,湖州,绍兴,金华,衢州,舟山,台州,丽水', '', 1, 1, NULL);
 INSERT INTO `t_area_email` (`name`, `area`, `email`, `is_virtual`, `is_active`, `remark`) VALUES ('福建', '福州,厦门,莆田,三明,泉州,漳州,南平,龙岩,宁德', '', 1, 1, NULL);
@@ -85,12 +86,15 @@ INSERT INTO `t_area_email` (`name`, `area`, `email`, `is_virtual`, `is_active`,
 INSERT INTO `t_area_email` (`name`, `area`, `email`, `is_virtual`, `is_active`, `remark`) VALUES ('贵州', '贵阳,六盘水,遵义,安顺,毕节,铜仁,黔东南苗族侗族自治州,黔南布依族苗族自治州,黔西南布依族苗族自治州', '', 1, 1, NULL);
 INSERT INTO `t_area_email` (`name`, `area`, `email`, `is_virtual`, `is_active`, `remark`) VALUES ('广西', '南宁,柳州,桂林,梧州,北海,防城港,钦州,贵港,玉林,百色,贺州,河池,来宾,崇左', '', 1, 1, NULL);
 INSERT INTO `t_area_email` (`name`, `area`, `email`, `is_virtual`, `is_active`, `remark`) VALUES ('海南', '海口,三亚,三沙,儋州,琼海,文昌,万宁,东方,澄迈,定安,屯昌,临高,白沙黎族自治县,昌江黎族自治县,乐东黎族自治县,陵水黎族自治县,保亭黎族苗族自治县,琼中黎族苗族自治县', '', 1, 1, NULL);
-INSERT INTO `t_area_email` (`name`, `area`, `email`, `is_virtual`, `is_active`, `remark`) VALUES ('广东', '珠海,汕头,佛山,韶关,湛江,肇庆,江门,茂名,惠州,梅州,汕尾,河源,阳江,清远,东莞,潮州,揭阳,云浮', '', 1, 1, NULL);
+INSERT INTO `t_area_email` (`name`, `area`, `email`, `is_virtual`, `is_active`, `remark`) VALUES ('广东_01', '珠海,汕头,佛山,韶关,湛江,肇庆,江门,茂名,惠州,梅州,汕尾,河源,阳江,清远,东莞,潮州,揭阳,云浮', '', 1, 1, NULL);
+INSERT INTO `t_area_email` (`name`, `area`, `email`, `is_virtual`, `is_active`, `remark`) VALUES ('广东_02', '深圳', '', 1, 1, NULL);
+INSERT INTO `t_area_email` (`name`, `area`, `email`, `is_virtual`, `is_active`, `remark`) VALUES ('广东_03', '广州,中山', '', 1, 1, NULL);
 INSERT INTO `t_area_email` (`name`, `area`, `email`, `is_virtual`, `is_active`, `remark`) VALUES ('西藏', '拉萨,日喀则,昌都,林芝,山南,那曲,阿里地区', '', 1, 1, NULL);
 INSERT INTO `t_area_email` (`name`, `area`, `email`, `is_virtual`, `is_active`, `remark`) VALUES ('云南', '昆明,曲靖,玉溪,保山,昭通,丽江,普洱,临沧,红河哈尼族彝族自治州,文山壮族苗族自治州,西双版纳傣族自治州,大理白族自治州,德宏傣族景颇族自治州,怒江傈僳族自治州,迪庆藏族自治州', '', 1, 1, NULL);
 
 
 
+
 -- ----------------------------
 -- Table structure for t_collect_data
 -- ----------------------------
@@ -136,6 +140,7 @@ CREATE TABLE `t_data`  (
   `province` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '招标单位省份',
   `city` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '招标单位城市',
   `address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '详细地点',
+  `budget` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '预算金额(单位:元)',
   `summary` text CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL COMMENT '招标摘要',
   `release_date` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '发布时间',
   `devices` varchar(1000) NULL DEFAULT NULL COMMENT '相关设备',