customerSave.php 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883
  1. <?php
  2. require_once 'conn.php';
  3. checkLogin();
  4. ?>
  5. <!DOCTYPE html>
  6. <html xmlns="http://www.w3.org/1999/xhtml">
  7. <head>
  8. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  9. <title>管理区域</title>
  10. <link rel="stylesheet" href="system/css/common.css" type="text/css" />
  11. <script src="system/js/jquery-1.7.2.min.js"></script>
  12. <script src="js/js.js"></script>
  13. </head>
  14. <body class="clear">
  15. <?php
  16. // Get query parameters
  17. $page = $_GET['Page'] ?? '';
  18. $keys = urlencode($_GET['Keys'] ?? '');
  19. $fliterBusiness = $_GET['fliterBusiness'] ?? '';
  20. $fliterDeal = $_GET['Deal'] ?? '';
  21. // Get form data
  22. $id = $_POST['id'] ?? '';
  23. $cs_code = textEncode($_POST['cs_code'] ?? '');
  24. $cs_company = textEncode($_POST['cs_company'] ?? '');
  25. $cs_country = $_POST['cs_country'] ?? '';
  26. $cs_from = $_POST['cs_from'] ?? '';
  27. $cs_address = textEncode($_POST['cs_address'] ?? '');
  28. $cs_type = textEncode($_POST['cs_type'] ?? '');
  29. $cs_belongclient = $_POST['cs_belongclient'] ?? '';
  30. $cs_addtime = $_POST['cs_addtime'] ?? '';
  31. $cs_updatetime = date('Y-m-d H:i:s');
  32. $cs_belong = $_SESSION['employee_id'];
  33. $cs_state = 1;
  34. $cs_deal = $_POST['cs_deal'] ?? '';
  35. $allowedit = $_POST['Permissions'] ?? '0';
  36. // Get contact information from the form
  37. $contacts = $_POST['contact'] ?? [];
  38. // Validate numeric values
  39. $allowedit = is_numeric($allowedit) ? $allowedit : 0;
  40. $cs_country = (is_numeric($cs_country) && $cs_country !== '') ? $cs_country : 0;
  41. $cs_from = (is_numeric($cs_from) && $cs_from !== '') ? $cs_from : 0;
  42. $cs_deal = (is_numeric($cs_deal) && $cs_deal !== '') ? $cs_deal : 1;
  43. $cs_type = (is_numeric($cs_type) && $cs_type !== '') ? $cs_type : 5;
  44. $cs_belongClient = (is_numeric($cs_belongclient) && $cs_belongclient !== '') ? $cs_belongclient : 0;
  45. $cs_note = htmlEncode($_POST['cs_note'] ?? '');
  46. $mytag = textEncode($_POST['mytag'] ?? '');
  47. $mytag = str_replace(['&#60;&#47;span&#62;&#60;span&#62;', '&#60;&#47;span&#62;', '&#60;span&#62;'], [',', '', ''], $mytag);
  48. $mytag = explode(',', $mytag);
  49. // Auto-detect source from code
  50. if (strpos($cs_code, ';1688') !== false) {
  51. $cs_from = 1; // 1688
  52. }
  53. if (strpos($cs_code, ';阿里') !== false) {
  54. $cs_from = 2; // International station
  55. }
  56. // Get the first contact for validation (if any)
  57. $primary_contact = !empty($contacts) ? current($contacts) : [];
  58. // Check contact-specific validation requirements based on source
  59. if ($allowedit != 1) {
  60. // Get the first contact's information for validation
  61. $contact_name = textEncode($primary_contact['contact_name'] ?? '');
  62. $tel_1 = textEncode($primary_contact['tel_1'] ?? '');
  63. $wechat_1 = textEncode($primary_contact['wechat_1'] ?? '');
  64. $whatsapp_1 = textEncode($primary_contact['whatsapp_1'] ?? '');
  65. $email_1 = textEncode($primary_contact['email_1'] ?? '');
  66. $alibaba_1 = textEncode($primary_contact['alibaba_1'] ?? '');
  67. $facebook_1 = textEncode($primary_contact['facebook_1'] ?? '');
  68. // Alibaba validation
  69. if (($cs_from == 1 || $cs_from == 2) && empty($alibaba_1)) {
  70. echo "<script>alert('阿里旺旺为必填项');history.back();</script>";
  71. exit;
  72. }
  73. // Website source validation
  74. if (strpos($cs_code, '官网') !== false) {
  75. $cs_from = 3;
  76. }
  77. if ($cs_from == 3 && empty($tel_1) && empty($whatsapp_1) && empty($wechat_1)) {
  78. echo "<script>alert('电话和WhatsApp为必填项');history.back();</script>";
  79. exit;
  80. }
  81. // Market customer validation
  82. if ($cs_from == 8 && empty($wechat_1)) {
  83. echo "<script>alert('微信为必填项');history.back();</script>";
  84. exit;
  85. }
  86. // Facebook validation
  87. if ($cs_from == 12 && empty($facebook_1)) {
  88. echo "<script>alert('Facebook为必填项');history.back();</script>";
  89. exit;
  90. }
  91. }
  92. // Determine action type
  93. $act = empty($id) || !is_numeric($id) ? 'addSave' : 'editSave';
  94. if ($act === 'editSave') {
  95. // Verify customer ownership - 将bind_param改为SQL拼接
  96. $id = intval($id); // 确保ID是整数,防止SQL注入
  97. $sql = "SELECT cs_belong FROM customer WHERE id = " . $id;
  98. $result = $conn->query($sql);
  99. if ($row = $result->fetch_assoc()) {
  100. if ($row['cs_belong'] != $cs_belong) {
  101. echo "<script>alert('抱歉,该客户属于另一业务,你没有权限修改');history.back();</script>";
  102. exit;
  103. }
  104. } else {
  105. echo "<script>alert('没有此客户!');history.back();</script>";
  106. exit;
  107. }
  108. }
  109. // Validate customer code
  110. if (empty($cs_code)) {
  111. echo "<script>alert('客户编码不能为空');history.back();</script>";
  112. exit;
  113. }
  114. $customer_id = is_numeric($id) ? intval($id) : 0;
  115. // Check for duplicate customer information
  116. $checkStr = "SELECT c.*, cc.*
  117. FROM customer c
  118. LEFT JOIN customer_contact cc ON c.id = cc.customer_id
  119. WHERE c.id != " . $customer_id." AND ( 1=2 ";
  120. $Dupli = "";
  121. /* 暂时不需要这些检查 START */
  122. // Company name similarity check
  123. //if (!empty($cs_company)) {
  124. // $companyWords = explode(' ', strtolower($cs_company));
  125. // foreach ($companyWords as $word) {
  126. // if (strlen($word) > 3) { // Only check words longer than 3 characters
  127. // $checkStr .= " OR LOWER(c.cs_company) LIKE '%" . $conn->real_escape_string($word) . "%'";
  128. // }
  129. // }
  130. //}
  131. // Address similarity check
  132. //if (!empty($cs_address)) {
  133. // $addressWords = explode(' ', strtolower($cs_address));
  134. // foreach ($addressWords as $word) {
  135. // if (strlen($word) > 3) { // Only check words longer than 3 characters
  136. // $checkStr .= " OR LOWER(c.cs_address) LIKE '%" . $conn->real_escape_string($word) . "%'";
  137. // }
  138. // }
  139. //}
  140. /* 暂时不需要这些检查 END */
  141. // Check all contacts for duplicates
  142. foreach ($contacts as $contact) {
  143. //遍历处理空格
  144. foreach ($contact as $key => $value) {
  145. $contact[$key] = trim($value);
  146. }
  147. // Check all phone numbers
  148. for ($i = 1; $i <= 3; $i++) {
  149. $tel_field = 'tel_' . $i;
  150. if (!empty($contact[$tel_field])) {
  151. $tel_format = numFormat($contact[$tel_field]);
  152. // Remove country code and spaces for better matching
  153. $tel_clean = preg_replace('/[^0-9]/', '', $tel_format);
  154. if(!empty($tel_clean))
  155. {
  156. $checkStr .= " OR cc.tel_1_format LIKE '%" . substr($tel_clean, -9) . "%'" .
  157. " OR cc.tel_2_format LIKE '%" . substr($tel_clean, -9) . "%'" .
  158. " OR cc.tel_3_format LIKE '%" . substr($tel_clean, -9) . "%'" .
  159. " OR cc.wechat_1 LIKE '%" . substr($tel_clean, -9) . "%'" .
  160. " OR cc.wechat_2 LIKE '%" . substr($tel_clean, -9) . "%'" .
  161. " OR cc.wechat_3 LIKE '%" . substr($tel_clean, -9) . "%'";
  162. $Dupli .= "电话" . $i . ":" . $contact[$tel_field] . " ";
  163. }
  164. }
  165. }
  166. // Check all email addresses
  167. for ($i = 1; $i <= 3; $i++) {
  168. $email_field = 'email_' . $i;
  169. if (!empty($contact[$email_field])) {
  170. $contact[$email_field]=trim($contact[$email_field]);
  171. $email = strtolower($contact[$email_field]);
  172. $checkStr .= " OR LOWER(cc.email_1) = '" . $conn->real_escape_string($email) . "'" .
  173. " OR LOWER(cc.email_2) = '" . $conn->real_escape_string($email) . "'" .
  174. " OR LOWER(cc.email_3) = '" . $conn->real_escape_string($email) . "'";
  175. $Dupli .= "邮箱" . $i . ":" . $contact[$email_field] . " ";
  176. }
  177. }
  178. // Check all WhatsApp numbers
  179. for ($i = 1; $i <= 3; $i++) {
  180. $whatsapp_field = 'whatsapp_' . $i;
  181. if (!empty($contact[$whatsapp_field])) {
  182. $whatsapp_format = numFormat($contact[$whatsapp_field]);
  183. $whatsapp_clean = preg_replace('/[^0-9]/', '', $whatsapp_format);
  184. if(!empty($whatsapp_clean))
  185. {
  186. $checkStr .= " OR cc.whatsapp_1_format LIKE '%" . substr($whatsapp_clean, -9) . "%'" .
  187. " OR cc.whatsapp_2_format LIKE '%" . substr($whatsapp_clean, -9) . "%'" .
  188. " OR cc.whatsapp_3_format LIKE '%" . substr($whatsapp_clean, -9) . "%'" .
  189. " OR cc.tel_1_format LIKE '%" . substr($whatsapp_clean, -9) . "%'" .
  190. " OR cc.tel_2_format LIKE '%" . substr($whatsapp_clean, -9) . "%'" .
  191. " OR cc.tel_3_format LIKE '%" . substr($whatsapp_clean, -9) . "%'";
  192. $Dupli .= "WhatsApp" . $i . ":" . $contact[$whatsapp_field] . " ";
  193. }
  194. }
  195. }
  196. // Check all WeChat accounts
  197. for ($i = 1; $i <= 3; $i++) {
  198. $wechat_field = 'wechat_' . $i;
  199. if (!empty($contact[$wechat_field])) {
  200. $wechat = $contact[$wechat_field];
  201. $checkStr .= " OR cc.wechat_1 LIKE '%" . $conn->real_escape_string($wechat) . "%'" .
  202. " OR cc.wechat_2 LIKE '%" . $conn->real_escape_string($wechat) . "%'" .
  203. " OR cc.wechat_3 LIKE '%" . $conn->real_escape_string($wechat) . "%'" .
  204. " OR cc.tel_1_format LIKE '%" . $conn->real_escape_string($wechat) . "%'" .
  205. " OR cc.tel_2_format LIKE '%" . $conn->real_escape_string($wechat) . "%'" .
  206. " OR cc.tel_3_format LIKE '%" . $conn->real_escape_string($wechat) . "%'";
  207. $Dupli .= "微信" . $i . ":" . $contact[$wechat_field] . " ";
  208. }
  209. }
  210. // Check all LinkedIn accounts
  211. for ($i = 1; $i <= 3; $i++) {
  212. $linkedin_field = 'linkedin_' . $i;
  213. if (!empty($contact[$linkedin_field])) {
  214. $linkedin = strtolower($contact[$linkedin_field]);
  215. $checkStr .= " OR LOWER(cc.linkedin_1) LIKE '%" . $conn->real_escape_string($linkedin) . "%'" .
  216. " OR LOWER(cc.linkedin_2) LIKE '%" . $conn->real_escape_string($linkedin) . "%'" .
  217. " OR LOWER(cc.linkedin_3) LIKE '%" . $conn->real_escape_string($linkedin) . "%'";
  218. $Dupli .= "LinkedIn" . $i . ":" . $contact[$linkedin_field] . " ";
  219. }
  220. }
  221. // Check all Facebook accounts
  222. for ($i = 1; $i <= 3; $i++) {
  223. $facebook_field = 'facebook_' . $i;
  224. if (!empty($contact[$facebook_field])) {
  225. $facebook = strtolower($contact[$facebook_field]);
  226. $checkStr .= " OR LOWER(cc.facebook_1) LIKE '%" . $conn->real_escape_string($facebook) . "%'" .
  227. " OR LOWER(cc.facebook_2) LIKE '%" . $conn->real_escape_string($facebook) . "%'" .
  228. " OR LOWER(cc.facebook_3) LIKE '%" . $conn->real_escape_string($facebook) . "%'";
  229. $Dupli .= "Facebook" . $i . ":" . $contact[$facebook_field] . " ";
  230. }
  231. }
  232. // Check all Alibaba accounts
  233. for ($i = 1; $i <= 3; $i++) {
  234. $alibaba_field = 'alibaba_' . $i;
  235. if (!empty($contact[$alibaba_field])) {
  236. $alibaba = strtolower($contact[$alibaba_field]);
  237. if (strlen($alibaba) < 10) {
  238. $checkStr .= " OR LOWER(cc.alibaba_1) LIKE '" . $conn->real_escape_string($alibaba) . "'" .
  239. " OR LOWER(cc.alibaba_2) LIKE '" . $conn->real_escape_string($alibaba) . "'" .
  240. " OR LOWER(cc.alibaba_3) LIKE '" . $conn->real_escape_string($alibaba) . "'";
  241. } else {
  242. $alibaba_clean = preg_replace('/[^0-9a-zA-Z]/', '', $alibaba);
  243. $checkStr .= " OR LOWER(cc.alibaba_1) LIKE '%" . substr($alibaba_clean, -9) . "%'" .
  244. " OR LOWER(cc.alibaba_2) LIKE '%" . substr($alibaba_clean, -9) . "%'" .
  245. " OR LOWER(cc.alibaba_3) LIKE '%" . substr($alibaba_clean, -9) . "%'";
  246. }
  247. $Dupli .= "阿里旺旺" . $i . ":" . $contact[$alibaba_field] . " ";
  248. }
  249. }
  250. }
  251. $checkStr .= " ) ORDER BY c.id ASC";
  252. if ($allowedit != 1) {
  253. $result = $conn->query($checkStr);
  254. if ($result && $result->num_rows > 0) {
  255. $row = $result->fetch_assoc();
  256. // Get owner name
  257. $ownerResult = $conn->query("SELECT em_user FROM employee WHERE id = " . $row['cs_belong']);
  258. $ownerRow = $ownerResult->fetch_assoc();
  259. $owner = textUncode($ownerRow['em_user']);
  260. // Determine who entered first
  261. if (strtotime($cs_addtime) > strtotime($row['cs_addtime'])) {
  262. $tstr = "INSERT INTO logrecord (loginName, loginIp, loginTime, loginAct) VALUES ('" .
  263. $_SESSION['employee_name'] . "', '" . getIp() . "', '" . date('Y-m-d H:i:s') . "', '" .
  264. $_SESSION['employee_name'] . "编辑客户\"" . $cs_code . "\",该客户与\"" .
  265. textUncode($row['cs_code']) . "\"高度类似,<br>重复项为:" . $Dupli . "<br>客户由:" .
  266. $_SESSION['employee_name'] . $cs_addtime . "首次录入')";
  267. } else {
  268. $tstr = "INSERT INTO logrecord (loginName, loginIp, loginTime, loginAct) VALUES ('" .
  269. $_SESSION['employee_name'] . "', '" . getIp() . "', '" . date('Y-m-d H:i:s') . "', '" .
  270. $_SESSION['employee_name'] . "编辑客户\"" . $cs_code . "\",该客户与\"" .
  271. textUncode($row['cs_code']) . "\"高度类似,<br>重复项为:" . $Dupli . "<br>客户由:" .
  272. $owner . $row['cs_addtime'] . "首次录入')";
  273. }
  274. $conn->query($tstr);
  275. echo "<script>alert('warning.1.录入信息\\n与" . $owner . "客户编号:" . textUncode($row['cs_code']) .
  276. "\\n高度类似,未能保存,请联系管理员核实!');history.back();</script>";
  277. exit;
  278. }
  279. else
  280. {
  281. //全文检索再检查一次
  282. //先去掉联系方式中的特殊字符
  283. //用联系方式进行全文fullindex检索,用相关性分数大于百分70 的进行检查
  284. // 根据不同联系方式类型进行专门检查
  285. $duplicateFound = false;
  286. $matchDetails = '';
  287. $matchScore = 0;
  288. $matchCustomerId = 0;
  289. $matchCustomerCode = '';
  290. $matchOwner = '';
  291. $matchAddTime = '';
  292. // 编辑模式下需要排除自己的ID
  293. $excludeId = ($act === 'editSave' && is_numeric($id)) ? intval($id) : 0;
  294. // 1. 优先检查邮箱 - 邮箱是最精确的匹配
  295. $emailTerms = [];
  296. foreach ($contacts as $contact) {
  297. for ($i = 1; $i <= 3; $i++) {
  298. $field = 'email_' . $i;
  299. if (!empty($contact[$field])) {
  300. $email = strtolower(trim($contact[$field]));
  301. if (strpos($email, '@') !== false) {
  302. $emailTerms[] = $email;
  303. }
  304. }
  305. }
  306. }
  307. if (!empty($emailTerms)) {
  308. $emailQuery = "SELECT c.id, c.cs_code, c.cs_belong, c.cs_addtime, cc.email_1, cc.email_2, cc.email_3
  309. FROM customer c
  310. JOIN customer_contact cc ON c.id = cc.customer_id
  311. WHERE c.cs_belong != " . $_SESSION['employee_id'] . "
  312. AND c.id != " . $excludeId . " AND (";
  313. $emailConditions = [];
  314. foreach ($emailTerms as $email) {
  315. $emailConditions[] = "cc.email_1 = '" . $conn->real_escape_string($email) . "'";
  316. $emailConditions[] = "cc.email_2 = '" . $conn->real_escape_string($email) . "'";
  317. $emailConditions[] = "cc.email_3 = '" . $conn->real_escape_string($email) . "'";
  318. }
  319. $emailQuery .= implode(" OR ", $emailConditions) . ") LIMIT 1";
  320. $emailResult = $conn->query($emailQuery);
  321. if ($emailResult && $emailResult->num_rows > 0) {
  322. $row = $emailResult->fetch_assoc();
  323. $matchCustomerId = $row['id'];
  324. $matchCustomerCode = $row['cs_code'];
  325. $matchOwner = $row['cs_belong'];
  326. $matchAddTime = $row['cs_addtime'];
  327. $matchDetails = "邮箱完全匹配";
  328. $matchScore = 0.95; // 邮箱精确匹配,高可信度
  329. $duplicateFound = true;
  330. }
  331. }
  332. // 2. 检查电话号码与WhatsApp - 清理后进行后缀匹配
  333. if (!$duplicateFound) {
  334. $phoneTerms = [];
  335. foreach ($contacts as $contact) {
  336. // 收集所有电话号码
  337. for ($i = 1; $i <= 3; $i++) {
  338. $fields = ['tel_' . $i, 'whatsapp_' . $i];
  339. foreach ($fields as $field) {
  340. if (!empty($contact[$field])) {
  341. $cleaned = preg_replace('/[^0-9]/', '', $contact[$field]);
  342. if (strlen($cleaned) > 7) { // 至少8位有效数字
  343. $phoneTerms[] = $cleaned;
  344. }
  345. }
  346. }
  347. }
  348. }
  349. if (!empty($phoneTerms)) {
  350. $phoneQuery = "SELECT c.id, c.cs_code, c.cs_belong, c.cs_addtime,
  351. cc.tel_1_format, cc.tel_2_format, cc.tel_3_format,
  352. cc.whatsapp_1_format, cc.whatsapp_2_format, cc.whatsapp_3_format
  353. FROM customer c
  354. JOIN customer_contact cc ON c.id = cc.customer_id
  355. WHERE c.cs_belong != " . $_SESSION['employee_id'] . "
  356. AND c.id != " . $excludeId . " AND (";
  357. $phoneConditions = [];
  358. foreach ($phoneTerms as $phone) {
  359. // 使用后8位进行匹配,避免国家代码等差异
  360. $suffix = substr($phone, -8);
  361. if (strlen($suffix) == 8) {
  362. $phoneConditions[] = "cc.tel_1_format LIKE '%" . $conn->real_escape_string($suffix) . "'";
  363. $phoneConditions[] = "cc.tel_2_format LIKE '%" . $conn->real_escape_string($suffix) . "'";
  364. $phoneConditions[] = "cc.tel_3_format LIKE '%" . $conn->real_escape_string($suffix) . "'";
  365. $phoneConditions[] = "cc.whatsapp_1_format LIKE '%" . $conn->real_escape_string($suffix) . "'";
  366. $phoneConditions[] = "cc.whatsapp_2_format LIKE '%" . $conn->real_escape_string($suffix) . "'";
  367. $phoneConditions[] = "cc.whatsapp_3_format LIKE '%" . $conn->real_escape_string($suffix) . "'";
  368. }
  369. }
  370. if (!empty($phoneConditions)) {
  371. $phoneQuery .= implode(" OR ", $phoneConditions) . ") LIMIT 1";
  372. $phoneResult = $conn->query($phoneQuery);
  373. if ($phoneResult && $phoneResult->num_rows > 0) {
  374. $row = $phoneResult->fetch_assoc();
  375. $matchCustomerId = $row['id'];
  376. $matchCustomerCode = $row['cs_code'];
  377. $matchOwner = $row['cs_belong'];
  378. $matchAddTime = $row['cs_addtime'];
  379. $matchDetails = "电话号码后8位匹配";
  380. $matchScore = 0.90; // 电话匹配,高可信度
  381. $duplicateFound = true;
  382. }
  383. }
  384. }
  385. }
  386. // 3. 检查社交媒体账号 (alibaba/wechat/facebook/linkedin)
  387. if (!$duplicateFound) {
  388. $socialTerms = [];
  389. $socialFields = [
  390. 'alibaba' => '阿里旺旺',
  391. 'wechat' => '微信',
  392. 'facebook' => 'Facebook',
  393. 'linkedin' => 'LinkedIn'
  394. ];
  395. foreach ($contacts as $contact) {
  396. foreach ($socialFields as $field => $label) {
  397. for ($i = 1; $i <= 3; $i++) {
  398. $fieldName = $field . '_' . $i;
  399. if (!empty($contact[$fieldName])) {
  400. $value = trim($contact[$fieldName]);
  401. if (strlen($value) > 3) { // 至少4个字符
  402. $socialTerms[] = [
  403. 'type' => $field,
  404. 'label' => $label,
  405. 'value' => $value
  406. ];
  407. }
  408. }
  409. }
  410. }
  411. }
  412. if (!empty($socialTerms)) {
  413. foreach ($socialTerms as $term) {
  414. $field = $term['type'];
  415. $value = $term['value'];
  416. $label = $term['label'];
  417. // 根据社交媒体类型构建不同的查询
  418. $socialQuery = "SELECT c.id, c.cs_code, c.cs_belong, c.cs_addtime FROM customer c
  419. JOIN customer_contact cc ON c.id = cc.customer_id
  420. WHERE c.cs_belong != " . $_SESSION['employee_id'] . "
  421. AND c.id != " . $excludeId . " AND (";
  422. // 根据社交账号类型确定匹配方式
  423. if ($field == 'alibaba' || $field == 'wechat') {
  424. // 阿里旺旺和微信用精确匹配
  425. $socialQuery .=
  426. "cc.{$field}_1 = '" . $conn->real_escape_string($value) . "' OR " .
  427. "cc.{$field}_2 = '" . $conn->real_escape_string($value) . "' OR " .
  428. "cc.{$field}_3 = '" . $conn->real_escape_string($value) . "'";
  429. } else {
  430. // Facebook和LinkedIn用模糊匹配
  431. $socialQuery .=
  432. "cc.{$field}_1 LIKE '%" . $conn->real_escape_string($value) . "%' OR " .
  433. "cc.{$field}_2 LIKE '%" . $conn->real_escape_string($value) . "%' OR " .
  434. "cc.{$field}_3 LIKE '%" . $conn->real_escape_string($value) . "%'";
  435. }
  436. $socialQuery .= ") LIMIT 1";
  437. $socialResult = $conn->query($socialQuery);
  438. if ($socialResult && $socialResult->num_rows > 0) {
  439. $row = $socialResult->fetch_assoc();
  440. $matchCustomerId = $row['id'];
  441. $matchCustomerCode = $row['cs_code'];
  442. $matchOwner = $row['cs_belong'];
  443. $matchAddTime = $row['cs_addtime'];
  444. $matchDetails = $label . "账号匹配";
  445. // 不同社交媒体账号的可信度
  446. switch ($field) {
  447. case 'alibaba':
  448. $matchScore = 0.85;
  449. break;
  450. case 'wechat':
  451. $matchScore = 0.85;
  452. break;
  453. case 'facebook':
  454. $matchScore = 0.80;
  455. break;
  456. case 'linkedin':
  457. $matchScore = 0.80;
  458. break;
  459. default:
  460. $matchScore = 0.75;
  461. }
  462. $duplicateFound = true;
  463. break; // 找到匹配就退出循环
  464. }
  465. }
  466. }
  467. }
  468. // 4. 最后尝试全文检索 - 作为补充检测手段
  469. if (!$duplicateFound) {
  470. // 准备全文检索字符串
  471. $searchTerms = [];
  472. // 处理所有联系人信息用于检索
  473. foreach ($contacts as $contact) {
  474. // 添加联系人名称
  475. if (!empty($contact['contact_name'])) {
  476. $searchTerms[] = textUncode($contact['contact_name']);
  477. }
  478. // 所有联系方式的组合检索
  479. $contactFields = [
  480. 'tel', 'email', 'whatsapp', 'wechat',
  481. 'linkedin', 'facebook', 'alibaba'
  482. ];
  483. foreach ($contactFields as $fieldType) {
  484. for ($i = 1; $i <= 3; $i++) {
  485. $field = $fieldType . '_' . $i;
  486. if (!empty($contact[$field])) {
  487. // 针对不同类型的联系方式进行不同清理
  488. if ($fieldType == 'tel' || $fieldType == 'whatsapp') {
  489. $cleaned = preg_replace('/[^0-9]/', '', $contact[$field]);
  490. if (strlen($cleaned) > 5) {
  491. $searchTerms[] = $cleaned;
  492. }
  493. } else if ($fieldType == 'email') {
  494. $cleaned = strtolower(trim($contact[$field]));
  495. if (strpos($cleaned, '@') !== false) {
  496. $searchTerms[] = $cleaned;
  497. }
  498. } else {
  499. $searchTerms[] = trim($contact[$field]);
  500. }
  501. }
  502. }
  503. }
  504. }
  505. // 如果有搜索条件
  506. if (!empty($searchTerms)) {
  507. // 创建MATCH AGAINST语句的词条
  508. $searchStr = implode(' ', array_unique(array_filter($searchTerms)));
  509. // 确保搜索字符串不为空
  510. if (!empty($searchStr)) {
  511. // 构建全文检索SQL
  512. $ftQuery = "SELECT c.id, c.cs_code, c.cs_belong, c.cs_addtime,
  513. MATCH( cc.tel_1, cc.tel_2, cc.tel_3,
  514. cc.email_1, cc.email_2, cc.email_3,
  515. cc.whatsapp_1, cc.whatsapp_2, cc.whatsapp_3,
  516. cc.wechat_1, cc.wechat_2, cc.wechat_3
  517. )
  518. AGAINST('" . $conn->real_escape_string($searchStr) . "' IN NATURAL LANGUAGE MODE) AS score
  519. FROM customer c
  520. JOIN customer_contact cc ON c.id = cc.customer_id
  521. WHERE c.id != " . $excludeId . "
  522. HAVING score > 0.7
  523. ORDER BY score DESC
  524. LIMIT 1";
  525. $ftResult = $conn->query($ftQuery);
  526. if(!($ftResult && $ftResult->num_rows > 0 ))
  527. {
  528. $ftQuery = "SELECT c.id, c.cs_code, c.cs_belong, c.cs_addtime,
  529. MATCH( cc.alibaba_1, cc.alibaba_2, cc.alibaba_3,
  530. cc.facebook_1, cc.facebook_2, cc.facebook_3,
  531. cc.linkedin_1, cc.linkedin_2, cc.linkedin_3)
  532. AGAINST('" . $conn->real_escape_string($searchStr) . "' IN NATURAL LANGUAGE MODE) AS score
  533. FROM customer c
  534. JOIN customer_contact cc ON c.id = cc.customer_id
  535. WHERE c.id != " . $excludeId . "
  536. HAVING score > 0.7
  537. ORDER BY score DESC
  538. LIMIT 1";
  539. $ftResult = $conn->query($ftQuery);
  540. }
  541. if ($ftResult && $ftResult->num_rows > 0) {
  542. $row = $ftResult->fetch_assoc();
  543. $matchCustomerId = $row['id'];
  544. $matchCustomerCode = $row['cs_code'];
  545. $matchOwner = $row['cs_belong'];
  546. $matchAddTime = $row['cs_addtime'];
  547. $matchDetails = "全文检索相似度" . number_format($row['score'] * 100, 1) . "%";
  548. $matchScore = $row['score'];
  549. $duplicateFound = true;
  550. }
  551. }
  552. }
  553. }
  554. // 如果找到重复客户,记录并提示
  555. if ($duplicateFound) {
  556. // 获取客户所有者姓名
  557. $ownerResult = $conn->query("SELECT em_user FROM employee WHERE id = " . $matchOwner);
  558. $ownerRow = $ownerResult->fetch_assoc();
  559. $owner = textUncode($ownerRow['em_user']);
  560. // 确定谁先录入
  561. if (strtotime($cs_addtime) > strtotime($matchAddTime)) {
  562. $tstr = "INSERT INTO logrecord (loginName, loginIp, loginTime, loginAct) VALUES ('" .
  563. $_SESSION['employee_name'] . "', '" . getIp() . "', '" . date('Y-m-d H:i:s') . "', '" .
  564. $_SESSION['employee_name'] . "编辑客户\"" . $cs_code . "\",该客户与\"" .
  565. textUncode($matchCustomerCode) . "\"存在重复,<br>匹配类型:" . $matchDetails .
  566. "<br>客户由:" . $owner . $matchAddTime . "首次录入')";
  567. } else {
  568. $tstr = "INSERT INTO logrecord (loginName, loginIp, loginTime, loginAct) VALUES ('" .
  569. $_SESSION['employee_name'] . "', '" . getIp() . "', '" . date('Y-m-d H:i:s') . "', '" .
  570. $_SESSION['employee_name'] . "编辑客户\"" . $cs_code . "\",该客户与\"" .
  571. textUncode($matchCustomerCode) . "\"存在重复,<br>匹配类型:" . $matchDetails .
  572. "<br>客户由:" . $_SESSION['employee_name'] . $cs_addtime . "首次录入')";
  573. }
  574. $conn->query($tstr);
  575. echo "<script>alert('warning.2.录入信息\\n与" . $owner . "客户编号:" . textUncode($matchCustomerCode) .
  576. "\\存在重复(" . $matchDetails . "),未能保存\\n请联系管理员核实!');history.back();</script>";
  577. exit;
  578. }
  579. }
  580. }
  581. // Save or update customer data
  582. if ($act == "editSave" || $allowedit == 1) {
  583. $hrefstr = "/customers.php?Keys=" . $keys . "&fliterBusiness=" . $fliterBusiness .
  584. "&fliterDeal=" . $fliterDeal . "&Page=" . $page;
  585. // 更新客户基本信息
  586. $updateSql = "UPDATE customer SET
  587. cs_code='" . $conn->real_escape_string($cs_code) . "',
  588. cs_company='" . $conn->real_escape_string($cs_company) . "',
  589. cs_country=" . $cs_country . ",
  590. cs_from=" . $cs_from . ",
  591. cs_address='" . $conn->real_escape_string($cs_address) . "',
  592. cs_updatetime='" . $cs_updatetime . "',
  593. cs_belong=" . $cs_belong . ",
  594. cs_belongclient=" . $cs_belongClient . ",
  595. cs_state=" . $cs_state . ",
  596. cs_deal=" . $cs_deal . ",
  597. cs_note='" . $conn->real_escape_string($cs_note) . "'";
  598. // 处理cs_dealdate
  599. if ($cs_deal == 3) {
  600. $updateSql .= ", cs_dealdate = CASE WHEN cs_dealdate IS NULL THEN NOW() ELSE cs_dealdate END";
  601. }
  602. $updateSql .= " WHERE id=" . intval($id);
  603. $conn->query($updateSql);
  604. // 处理联系人信息 - 首先删除已有的不在提交列表中的联系人
  605. $existingContactIds = [];
  606. foreach ($contacts as $contact) {
  607. if (!empty($contact['id'])) {
  608. $existingContactIds[] = (int)$contact['id'];
  609. }
  610. }
  611. if (!empty($existingContactIds)) {
  612. $idsToKeep = implode(',', $existingContactIds);
  613. $deleteContactsSql = "DELETE FROM customer_contact WHERE customer_id = " . intval($id) .
  614. " AND id NOT IN (" . $idsToKeep . ")";
  615. } else {
  616. $deleteContactsSql = "DELETE FROM customer_contact WHERE customer_id = " . intval($id);
  617. }
  618. $conn->query($deleteContactsSql);
  619. // 处理联系人信息 - 更新或添加联系人
  620. foreach ($contacts as $contact) {
  621. $contact_id = !empty($contact['id']) ? (int)$contact['id'] : 0;
  622. $contact_name = textEncode($contact['contact_name'] ?? '');
  623. // 准备SQL字段和值
  624. $fields = ['contact_name'];
  625. $values = ["'" . $conn->real_escape_string($contact_name) . "'"];
  626. $updates = ["contact_name = '" . $conn->real_escape_string($contact_name) . "'"];
  627. // 处理所有联系方式类型
  628. $methodTypes = ['tel', 'email', 'whatsapp', 'wechat', 'linkedin', 'facebook', 'alibaba'];
  629. foreach ($methodTypes as $type) {
  630. for ($i = 1; $i <= 3; $i++) {
  631. $field = $type . '_' . $i;
  632. $format_field = $field . '_format';
  633. $bu_field = $field . '_bu';
  634. $value = textEncode($contact[$field] ?? '');
  635. $format_value = ($type == 'tel' || $type == 'whatsapp') ? numFormat($value) : '';
  636. $bu_value = textEncode($contact[$bu_field] ?? $value);
  637. // 添加字段名
  638. $fields[] = $field;
  639. $fields[] = $bu_field;
  640. if ($type == 'tel' || $type == 'whatsapp') {
  641. $fields[] = $format_field;
  642. }
  643. // 添加值
  644. $values[] = "'" . $conn->real_escape_string($value) . "'";
  645. $values[] = "'" . $conn->real_escape_string($bu_value) . "'";
  646. if ($type == 'tel' || $type == 'whatsapp') {
  647. $values[] = "'" . $conn->real_escape_string($format_value) . "'";
  648. }
  649. // 添加更新语句
  650. $updates[] = $field . " = '" . $conn->real_escape_string($value) . "'";
  651. $updates[] = $bu_field . " = '" . $conn->real_escape_string($bu_value) . "'";
  652. if ($type == 'tel' || $type == 'whatsapp') {
  653. $updates[] = $format_field . " = '" . $conn->real_escape_string($format_value) . "'";
  654. }
  655. }
  656. }
  657. if ($contact_id > 0) {
  658. // 更新已有联系人
  659. $updateContactSql = "UPDATE customer_contact SET " .
  660. implode(", ", $updates) . ", updated_at = NOW() " .
  661. "WHERE id = " . $contact_id . " AND customer_id = " . intval($id);
  662. $conn->query($updateContactSql);
  663. } else {
  664. // 添加新联系人
  665. $insertContactSql = "INSERT INTO customer_contact (" .
  666. implode(", ", $fields) . ", customer_id, created_at, updated_at) VALUES (" .
  667. implode(", ", $values) . ", " . intval($id) . ", NOW(), NOW())";
  668. $conn->query($insertContactSql);
  669. }
  670. }
  671. // Update tags
  672. $conn->query("DELETE FROM tagtable WHERE customerId = " . intval($id));
  673. foreach ($mytag as $tag) {
  674. if (!empty(trim($tag))) {
  675. $tagSql = "INSERT INTO tagtable (tagName, employeeId, customerId) VALUES ('" .
  676. $conn->real_escape_string($tag) . "', " .
  677. intval($_SESSION['employee_id']) . ", " .
  678. intval($id) . ")";
  679. $conn->query($tagSql);
  680. }
  681. }
  682. echo "<script>location.href='$hrefstr';</script>";
  683. } else {
  684. // Insert new customer record
  685. $insertSql = "INSERT INTO customer (
  686. cs_code, cs_company, cs_country, cs_from, cs_address,
  687. cs_type, cs_addtime, cs_updatetime, cs_belong, cs_belongClient,
  688. cs_state, cs_deal, cs_note, cs_chain, is_silent, cs_dealdate
  689. ) VALUES (
  690. '" . $conn->real_escape_string($cs_code) . "',
  691. '" . $conn->real_escape_string($cs_company) . "',
  692. " . $cs_country . ",
  693. " . $cs_from . ",
  694. '" . $conn->real_escape_string($cs_address) . "',
  695. " . $cs_type . ",
  696. NOW(),
  697. NOW(),
  698. " . $cs_belong . ",
  699. " . $cs_belongClient . ",
  700. " . $cs_state . ",
  701. " . $cs_deal . ",
  702. '" . $conn->real_escape_string($cs_note) . "',
  703. " . $cs_belong . ",
  704. 0,
  705. " . ($cs_deal == 3 ? "NOW()" : "NULL") . "
  706. )";
  707. $conn->query($insertSql);
  708. $new_customer_id = $conn->insert_id;
  709. // Insert contact information for all contacts
  710. if ($new_customer_id > 0) {
  711. foreach ($contacts as $contact) {
  712. $contact_name = textEncode($contact['contact_name'] ?? '');
  713. // 准备SQL字段和值
  714. $fields = ['contact_name'];
  715. $values = ["'" . $conn->real_escape_string($contact_name) . "'"];
  716. // 处理所有联系方式类型
  717. $methodTypes = ['tel', 'email', 'whatsapp', 'wechat', 'linkedin', 'facebook', 'alibaba'];
  718. foreach ($methodTypes as $type) {
  719. for ($i = 1; $i <= 3; $i++) {
  720. $field = $type . '_' . $i;
  721. $format_field = $field . '_format';
  722. $bu_field = $field . '_bu';
  723. $value = textEncode($contact[$field] ?? '');
  724. $format_value = ($type == 'tel' || $type == 'whatsapp') ? numFormat($value) : '';
  725. $bu_value = textEncode($contact[$bu_field] ?? $value);
  726. // 添加字段名
  727. $fields[] = $field;
  728. $fields[] = $bu_field;
  729. if ($type == 'tel' || $type == 'whatsapp') {
  730. $fields[] = $format_field;
  731. }
  732. // 添加值
  733. $values[] = "'" . $conn->real_escape_string($value) . "'";
  734. $values[] = "'" . $conn->real_escape_string($bu_value) . "'";
  735. if ($type == 'tel' || $type == 'whatsapp') {
  736. $values[] = "'" . $conn->real_escape_string($format_value) . "'";
  737. }
  738. }
  739. }
  740. // 添加新联系人
  741. $insertContactSql = "INSERT INTO customer_contact (" .
  742. implode(", ", $fields) . ", customer_id, created_at, updated_at) VALUES (" .
  743. implode(", ", $values) . ", " . $new_customer_id . ", NOW(), NOW())";
  744. $conn->query($insertContactSql);
  745. }
  746. // Save tags for new customer
  747. foreach ($mytag as $tag) {
  748. if (!empty(trim($tag))) {
  749. $tagSql = "INSERT INTO tagtable (tagName, employeeId, customerId) VALUES ('" .
  750. $conn->real_escape_string($tag) . "', " .
  751. intval($_SESSION['employee_id']) . ", " .
  752. intval($new_customer_id) . ")";
  753. $conn->query($tagSql);
  754. }
  755. }
  756. }
  757. echo "<script>location.href='customerAdd.php';</script>";
  758. }
  759. ?>
  760. </body>
  761. </html>