Explorar o código

退回功能修改

mxs hai 7 meses
pai
achega
b2705dc67f

+ 45 - 27
backend/script/script.go

@@ -155,31 +155,42 @@ func (glvm *GLVm) BindLuaState(state *lua.LState) {
 	}))
 }
 
+func (glvm *GLVm) CloseTabs() {
+	if b := glvm.B; b != nil {
+		b.CancelFn()
+		b.Ctx = nil
+		b.CancelFn = nil
+	}
+}
+
 // findTab 根据标题、url找tab
 func (b *GLBrowser) findTabContext(tabTitle, tabUrl string, timeoutInt64 int64) (ctx context.Context, err error) {
-	if timeoutInt64 == 0 {
-		timeoutInt64 = 5000
-	}
-	timeout := time.Duration(timeoutInt64) * time.Millisecond
-	if tabTitle == "" && tabUrl == "" {
-		ctx, _ = context.WithTimeout(b.Ctx, timeout)
-		return ctx, nil
-	} else {
-		ts, err := chromedp.Targets(b.Ctx)
-		if err != nil {
-			return nil, err
+	if b.Ctx != nil {
+		if timeoutInt64 == 0 {
+			timeoutInt64 = 5000
 		}
-		for _, t := range ts {
-			if (tabTitle != "" && strings.Contains(t.Title, tabTitle)) || (tabUrl != "" && strings.Contains(t.URL, tabUrl)) {
-				// log.Printf("find tab param<title,url>: %s %s found %s %s", tabTitle, tabUrl,
-				// 	t.Title, t.URL)
-				newCtx, _ := chromedp.NewContext(b.Ctx, chromedp.WithTargetID(t.TargetID))
-				ctx, _ = context.WithTimeout(newCtx, timeout)
-				return ctx, nil
+		timeout := time.Duration(timeoutInt64) * time.Millisecond
+		if tabTitle == "" && tabUrl == "" {
+			ctx, _ = context.WithTimeout(b.Ctx, timeout)
+			return ctx, nil
+		} else {
+			ts, err := chromedp.Targets(b.Ctx)
+			if err != nil {
+				return nil, err
+			}
+			for _, t := range ts {
+				if (tabTitle != "" && strings.Contains(t.Title, tabTitle)) || (tabUrl != "" && strings.Contains(t.URL, tabUrl)) {
+					// log.Printf("find tab param<title,url>: %s %s found %s %s", tabTitle, tabUrl,
+					// 	t.Title, t.URL)
+					newCtx, _ := chromedp.NewContext(b.Ctx, chromedp.WithTargetID(t.TargetID))
+					ctx, _ = context.WithTimeout(newCtx, timeout)
+					return ctx, nil
+				}
 			}
 		}
+		return nil, errors.New("can't find tab")
 	}
-	return nil, errors.New("can't find tab")
+	return nil, errors.New("context is error")
 }
 
 // CloseTabs 关闭页面
@@ -518,7 +529,7 @@ func (b *GLBrowser) BindLuaState(s *lua.LState, recordId string) {
 		}
 		return 1
 	}))
-
+	//等待元素加载
 	s.SetGlobal("browser_waitvisible", s.NewFunction(func(l *lua.LState) int {
 		fmt.Println("---browser_waitvisible---")
 		tabTitle := l.ToString(-5)
@@ -535,8 +546,7 @@ func (b *GLBrowser) BindLuaState(s *lua.LState, recordId string) {
 		}
 		return 1
 	}))
-
-	//点击
+	//下载附件
 	s.SetGlobal("browser_downloadfile", s.NewFunction(func(l *lua.LState) int {
 		tabTitle := l.ToString(-6)
 		tabUrl := l.ToString(-5)
@@ -553,7 +563,6 @@ func (b *GLBrowser) BindLuaState(s *lua.LState, recordId string) {
 		}
 		return 1
 	}))
-
 	//注册打开地址
 	s.SetGlobal("browser_navagite_download_res", s.NewFunction(func(l *lua.LState) int {
 		tabTitle := l.ToString(-7)
@@ -570,6 +579,13 @@ func (b *GLBrowser) BindLuaState(s *lua.LState, recordId string) {
 		}
 		return 1
 	}))
+	//发布时间格式化
+	s.SetGlobal("browser_publishtime", s.NewFunction(func(l *lua.LState) int {
+		text := l.ToString(-1)
+		publishtime := getPublitime(text)
+		l.Push(lua.LString(publishtime))
+		return 1
+	}))
 	//保存数据
 	s.SetGlobal("browser_savedata", s.NewFunction(func(l *lua.LState) int {
 		fmt.Println("---browser_upsertdata---")
@@ -591,12 +607,14 @@ func (b *GLBrowser) BindLuaState(s *lua.LState, recordId string) {
 			l.Push(lua.LString("err"))
 			l.Push(lua.LString("当前可下载量为0"))
 		} else {
-			resultTable := &lua.LTable{}
-			for i := 0; i < num && i < count; i++ {
-				resultTable.Append(MapToTable(Datas[i]))
+			if count < num {
+				num = count
 			}
+			data := Datas[:num]
+			Datas = Datas[num:]
+			tMap := MapToTable(map[string]interface{}{"data": data})
 			l.Push(lua.LString("ok"))
-			l.Push(resultTable)
+			l.Push(tMap.RawGetString("data"))
 		}
 		return 2
 	}))

+ 93 - 0
backend/script/util.go

@@ -3,7 +3,9 @@ package script
 import (
 	"fmt"
 	lua "github.com/yuin/gopher-lua"
+	qu "jygit.jydev.jianyu360.cn/data_processing/common_utils"
 	"log"
+	"regexp"
 	"time"
 )
 
@@ -123,3 +125,94 @@ func TableToMap(t *lua.LTable) map[string]interface{} {
 	})
 	return ret
 }
+
+func getPublitime(text string) string {
+	//取数字年月日时分秒
+	re := regexp.MustCompile(`(\d+)`)
+	matches := re.FindAllString(text, -1)
+	if len(matches) == 1 { //20240927 2024927 2024 927
+		return "0"
+	}
+	if len(matches) < 2 { //最少有年月 或月日
+		return "0"
+	}
+	y := padDigital(matches[0]) //年
+	m := padDigital(matches[1]) // 月
+	if len(matches) == 2 {      //年月或月日
+		if dateFormatCorret("year", y) && dateFormatCorret("month", m) { //年月
+			return formatTime(y, m, "", "", "", "")
+		} else if dateFormatCorret("month", y) && dateFormatCorret("day", m) { //月日
+			return formatTime("", y, m, "", "", "")
+		}
+	} else if len(matches) >= 3 {
+		d := padDigital(matches[2])
+		if len(matches) == 3 { //年月日(无月日时,时分秒的情况)
+			if dateFormatCorret("year", y) && dateFormatCorret("month", m) && dateFormatCorret("day", d) {
+				return formatTime(y, m, d, "", "", "")
+			}
+		} else if len(matches) >= 5 { //年月日时分
+			h := padDigital(matches[3])
+			mm := padDigital(matches[4])
+			if len(matches) == 5 { //年月日时分
+				if dateFormatCorret("year", y) && dateFormatCorret("month", m) && dateFormatCorret("day", d) && dateFormatCorret("hour", h) && dateFormatCorret("minute", mm) {
+					return formatTime(y, m, d, h, mm, "")
+				}
+			} else if len(matches) == 6 { //年月日时分秒
+				s := padDigital(matches[5])
+				if dateFormatCorret("year", y) && dateFormatCorret("month", m) && dateFormatCorret("day", d) && dateFormatCorret("hour", h) && dateFormatCorret("minute", mm) && dateFormatCorret("second", s) {
+					return formatTime(y, m, d, h, mm, s)
+				}
+			}
+		}
+	}
+	return "0"
+}
+func dateFormatCorret(stype, date string) bool {
+	switch stype {
+	case "year":
+		return len(date) == 4
+	case "month":
+		return len(date) <= 2 && date <= "12" && date >= "01"
+	case "day":
+		return len(date) <= 2 && date <= "31" && date >= "01"
+	case "hour":
+		return len(date) <= 2 && date <= "24" && date >= "00"
+	case "minute":
+		return len(date) <= 2 && date <= "59" && date >= "00"
+	case "second":
+		return len(date) <= 2 && date <= "59" && date >= "00"
+	}
+	return false
+}
+
+func padDigital(text string) string {
+	if len(text) < 2 {
+		return "0" + text
+	}
+	return text
+}
+
+func formatTime(year, month, day, hour, minute, second string) string {
+	now := time.Now()
+	if year == "" {
+		year = fmt.Sprint(now.Year())
+	} else if month == "" {
+		month = fmt.Sprint(now.Month())
+	} else if day == "" {
+		day = fmt.Sprint(now.Day())
+	} else if hour == "" {
+		hour = fmt.Sprint(now.Hour())
+	} else if minute == "" {
+		minute = fmt.Sprint(now.Minute())
+	} else if second == "" {
+		second = fmt.Sprint(now.Second())
+	}
+	return fmt.Sprintf("%4d-%02d-%02d %02d:%02d:%02d",
+		qu.IntAll(year),
+		qu.IntAll(month),
+		qu.IntAll(day),
+		qu.IntAll(hour),
+		qu.IntAll(minute),
+		qu.IntAll(second),
+	)
+}

+ 68 - 3
frontend/src/components/spider/jscodetpl.js

@@ -346,9 +346,13 @@ if ("{{.ContentCss}}" != "") {//正文内容
   tmp = document.querySelector("{{.ContentCss}}")
   if (tmp) {
     //TODO在这里写清洗逻辑
+    // 1. 按照元素索引位置删除
     //tmp.removeChild(tmp.children[0])
-    //或者
+    // 2. 删除子对象
     //if(tmp.querySelector("CSS选择器"))tmp.removeChild(tmp.querySelector("CSS选择器"))
+    // 3. 不删除,仅清空内容,同样的效果,没有不能删除孙子节点限制
+    //if(tmp.querySelector("CSS选择器"))tmp.querySelector("CSS选择器").innerHTML=''
+    
     ret["content"] = tmp.innerText
     ret["contentHtml"] = tmp.innerHTML
     var patchContent = false
@@ -381,7 +385,68 @@ let chineseCharacters = ret["content"]?ret["content"].match(regex):[];
 let chineseCharactersLen=chineseCharacters ? chineseCharacters.length : 0;
 if (chineseCharactersLen < 20 && ret["attachLinks"] && ret["attachLinks"].length>0) ret["content"] = '详情请访问原网页!'
 ret 
-    `},
+    `}, {
+            "name": "模版5",
+            "tooltip": "详情页日期提取,需要用正则提取",
+            "code": `
+var ret = {}
+var tmp = null
+
+if ("{{.TitleCss}}" != "") {//标题
+tmp = document.querySelector("{{.TitleCss}}")
+if (tmp) ret["title"] = tmp.getAttribute("title") || tmp.innerText
+}
+if ("{{.PublishUnitCss}}" != "") {//采购单位
+tmp = document.querySelector("{{.PublishUnitCss}}")
+if (tmp) ret["publishUnit"] = tmp.getAttribute("title") || tmp.innerText
+}
+if ("{{.PublishTimeCss}}" != "") {//发布时间
+tmp = document.querySelector("{{.PublishTimeCss}}")
+if (tmp) {
+    //        格式:2024/01/05                  2024-01-05                   2024年01月05日                   15:01:01 (仅时间,可以自己修改)
+    var regTpl = ["(\\\\d{4}/\\\\d{1,2}/\\\\d{1,2})","(\\\\d{4}-\\\\d{1,2}-\\\\d{1,2})","(\\\\d{4}年\\\\d{1,2}月\\\\d{1,2}日)","\\\\d{1,2}:\\\\d{1,2}:\\\\d{1,2})"]
+    //TODO 重点要修改这里的regTpl 索引号,也可以自己修改设置正则表达式
+    var reg = new RegExp(regTpl[0])
+    tmp = tmp.innerText.match(reg)
+    if(tmp && tmp.length>1)ret["publishTime"] = tmp[1]
+    }
+}
+if ("{{.ContentCss}}" != "") {//正文内容
+tmp = document.querySelector("{{.ContentCss}}")
+if (tmp) {
+ret["content"] = tmp.innerText
+ret["contentHtml"] = tmp.innerHTML
+var patchContent = false
+//处理详情页中的大图,大图作为附件使用
+const images = tmp.querySelectorAll("img");
+images.forEach((img, i) => {
+  if (img.width > 300) {
+    patchContent = true
+    const a = document.createElement("a");
+    a.href = img.src;
+    a.innerText = img.src;
+    tmp.appendChild(a);
+  }
+})
+}
+}
+if("{{.AttachCss}}"!=""){//附件
+tmp = document.querySelectorAll("{{.AttachCss}} a")
+let attach=[]
+if(tmp){
+    tmp.forEach((v,i)=>{
+        attach.push({title:v.getAttribute("title")||v.innerText,href:v.href})
+    })
+}
+ret["attachLinks"]=attach
+}
+//检查中文字符个数,少于20,修正正文内容
+let regex = /[\\u4e00-\\u9fa5]/g;
+let chineseCharacters = ret["content"]?ret["content"].match(regex):[];
+let chineseCharactersLen=chineseCharacters ? chineseCharacters.length : 0;
+if (chineseCharactersLen < 20 && ret["attachLinks"] && ret["attachLinks"].length>0) ret["content"] = '详情请访问原网页!'
+ret 
+`},
     ],
 
     AttachJsCode: `
@@ -442,7 +507,7 @@ document.querySelectorAll("{{.ListNextPageCss}}").forEach(link=>{
             "tooltip": "根据URL地址,模板化翻页",
             "code": `
 var href=window.location.href;
-var pageStr = href.match(/\/\d+).html/)
+var pageStr = href.match(/\\/\\d+).html/)
 var currentPage = 1
 if(pageStr&&pageStr.length>1)currentPage = parseInt(pageStr[1])
 currentPage+=1

+ 28 - 0
frontend/src/data/filters.js

@@ -89,3 +89,31 @@ export const spiderClaimOptions = [
     value: 2,
   },
 ]
+
+// 退回原因
+export const rollbackReasonList = [
+  {
+    label: '域名失效',
+    value: '域名失效',
+  },
+  {
+    label: '栏目缺失',
+    value: '栏目缺失',
+  },
+  {
+    label: '栏目改版',
+    value: '栏目改版',
+  },
+  {
+    label: '栏目拆分',
+    value: '栏目拆分',
+  },
+  {
+    label: '验证码反爬',
+    value: '验证码反爬',
+  },
+  {
+    label: '平台无法处理',
+    value: '平台无法处理',
+  },
+]

+ 48 - 20
frontend/src/views/CodeList.vue

@@ -127,6 +127,23 @@
         @save="dialogEvents.runSpiderConfigSave"
     />
     <VerifySpider ref="verifySpiderDialog" />
+    <el-dialog v-model="dialog.rollbackReason" title="选择退回原因" width="500">
+      <el-form>
+        <el-form-item label="退回原因">
+          <el-select v-model="filters.rollbackReason" placeholder="请选择">
+            <el-option v-for="item in filterConfig.rollbackOptions" :key="item.value" :label="item.label" :value="item.value" />
+          </el-select>
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button @click="dialog.rollbackReason = false">取消</el-button>
+          <el-button type="primary" @click="tableEvents.confirmRollbackReason(currentEditRow)">
+            确定
+          </el-button>
+        </div>
+      </template>
+    </el-dialog>
 </template>
 
 <script setup>
@@ -142,6 +159,7 @@ import RunSpiderDialog from "../components/spider/RunSpiderDialog.vue"
 import VerifySpider from "../components/spider/VerifySpider.vue"
 import { useCodeListFiltersWithRole } from '../composables/filter-options'
 import { USER_ROLE_ADMIN, USER_ROLE_DEVELOPER, USER_ROLE_REVIEWER } from '../data/user'
+import { rollbackReasonList } from "../data/index.js";
 import { Refresh, Search, Box } from '@element-plus/icons-vue'
 const isAdmin = computed(() => [USER_ROLE_ADMIN].includes(userRole.value))
 const router = useRouter();
@@ -163,7 +181,8 @@ const filterConfig = reactive({
             label: '全部',
             value: '-1',
         }
-    ]
+    ],
+    rollbackOptions: rollbackReasonList
 })
 
 // 选择器数据
@@ -176,6 +195,7 @@ const filters = reactive({
     modifyuser: '-1',
     // 认领状态
     claimtype: -1,
+    rollbackReason: undefined,
 })
 // 选择器数据(用来重置)
 const defaultFilters = {
@@ -216,6 +236,9 @@ const defaultListState = {
 const buttonState = reactive({
     renlingLoading: false
 })
+const dialog = reactive({
+  rollbackReason: false
+})
 
 // 当前编辑的row的数据
 const currentEditRow = ref({})
@@ -695,33 +718,38 @@ const tableEvents = {
     },
     handleRollback(_, row) {
         onlyClickHighlight(row, '_action_clicked_rollback')
-        // ElMessageBox.alert('确定退回?', '提示', {
-        //     customClass: 'j-confirm-message-box',
-        //     confirmButtonText: '确定',
-        //     callback: (action) => {
-        //         if (action === 'confirm') {
-        //             
-        //         }
-        //     },
+        currentEditRow.value = row
+        // ElMessageBox.confirm('确定退回?', '提示',
+        //     {
+        //         customClass: 'j-confirm-message-box',
+        //         type: 'warning',
+        //         confirmButtonText: '确定',
+        //         cancelButtonText: '取消',
+        //         showCancelButton: false,
+        //     }
+        // ).then(() => {
+        //     this.confirmRollback(row)
         // })
-        ElMessageBox.confirm('确定退回?', '提示',
-            {
-                customClass: 'j-confirm-message-box',
-                type: 'warning',
-                confirmButtonText: '确定',
-                cancelButtonText: '取消',
-                showCancelButton: false,
-            }
-        ).then(() => {
-            this.confirmRollback(row)
+        dialog.rollbackReason = true
+    },
+    confirmRollbackReason(row) {
+      if (!filters.rollbackReason) {
+        return ElMessage({
+          message: '请选择退回原因',
+          type: 'error',
+          duration: 3000,
         })
+      }
+      dialog.rollbackReason = false
+      tableEvents.confirmRollback(row)
     },
     confirmRollback(row) {
         const lua = getLuaParams(row)
         const param = {
-            stype: '退回'
+            stype: '退回',
         }
         lua.state = 12
+        lua.reason = filters.rollbackReason
         ServerActionUpdateCodeState({ lua: [lua], param }).then(r => {
             if (r.err === 1) {
                 ElMessage({

+ 48 - 13
frontend/src/views/CollectionList.vue

@@ -15,20 +15,20 @@
         </el-header>
         <el-main>
             <el-table ref="spiderTable" :data="listState.list" border stripe :row-style="getRowStyle" v-loading="listState.loading">
-                <el-table-column prop="comeintimeText" label="日期" width="110" align="left" show-overflow-tooltip></el-table-column>
+                <el-table-column prop="comeintimeText" label="日期" width="110" align="center" show-overflow-tooltip></el-table-column>
                 <!-- <el-table-column prop="proxyText" label="代理" align="left" show-overflow-tooltip></el-table-column>
                 <el-table-column prop="headlessText" label="浏览器" align="left" show-overflow-tooltip></el-table-column>
                 <el-table-column prop="imageText" label="图像" align="left" show-overflow-tooltip></el-table-column> -->
-                <el-table-column prop="listdatanum" label="列表量" align="left" show-overflow-tooltip></el-table-column>
+                <el-table-column prop="listdatanum" label="列表量" align="center" show-overflow-tooltip></el-table-column>
                 <el-table-column prop="needdownloadnum" label="待采量" align="center" show-overflow-tooltip></el-table-column>
                 <el-table-column prop="detaildatanum" label="成功量" align="center" show-overflow-tooltip></el-table-column>
-                <el-table-column prop="pushnum" label="推送量" show-overflow-tooltip></el-table-column>
-                <el-table-column prop="stateText" label="处理状态" width="100" show-overflow-tooltip>
+                <el-table-column prop="pushnum" label="推送量" align="center" show-overflow-tooltip></el-table-column>
+                <el-table-column prop="stateText" label="处理状态" align="center" width="100" show-overflow-tooltip>
                     <template #default="scope">
                         <div class="highlight-main">{{scope.row.stateText}}</div>
                     </template>
                 </el-table-column>
-                <el-table-column label="功能" width="220" align="center">
+                <el-table-column label="功能" width="250" align="center">
                     <template #default="scope">
                         <el-tooltip content="列表页采集" placement="top">
                             <el-button size="small" :class="{ active: scope.row._action_clicked_list_collect }" @click="tableEvents.handleListCollect(scope.$index, scope.row)">
@@ -50,16 +50,20 @@
                                 <el-icon><Position /></el-icon>
                             </el-button>
                         </el-tooltip>
+                        <el-tooltip content="清除记录" placement="top">
+                          <el-button size="small" :class="{ active: scope.row._action_clicked_remove_history }" @click="tableEvents.handleRemoveHistory(scope.$index, scope.row)">
+                            <el-icon><Delete /></el-icon>
+                          </el-button>
+                        </el-tooltip>
                     </template>
                 </el-table-column>
                 <el-table-column label="操作" width="120" align="center">
                     <template #default="scope">
-                        <el-tooltip content="清除记录" placement="top">
-                            <el-button size="small" :class="{ active: scope.row._action_clicked_remove_history }" @click="tableEvents.handleRemoveHistory(scope.$index, scope.row)">
-                                <el-icon><Delete /></el-icon>
+                        <el-dropdown>
+                            <el-button size="small" :class="{ active: scope.row._action_clicked_stop_download}" @click="tableEvents.stopDownloadData(scope.$index, scope.row)">
+                              中断
                             </el-button>
-                        </el-tooltip>
-
+                        </el-dropdown>
                         <el-dropdown>
                             <el-button size="small">导出</el-button>
                             <template #dropdown>
@@ -117,7 +121,7 @@
 import { ref, computed, reactive, watch } from 'vue'
 import { useStore } from 'vuex';
 import { ElMessage, ElMessageBox } from 'element-plus'
-import { ServerActionQlmAddRecord, QlmListDataDownload, QlmDetailDataDownload, ServerActionQlmRemoveRepeat, ServerActionQlmPushData, ServerActionQlmClearData } from "../../wailsjs/go/main/App"
+import { ServerActionQlmAddRecord,QlmStopDownloadData, QlmListDataDownload, QlmDetailDataDownload, ServerActionQlmRemoveRepeat, ServerActionQlmPushData, ServerActionQlmClearData } from "../../wailsjs/go/main/App"
 import { SelectSaveFilePath, QlmRunExportJsonFile, QlmRunExportExcelFile } from "../../wailsjs/go/main/App"
 
 import Breadcrumb from "../components/Breadcrumb.vue"
@@ -259,6 +263,7 @@ async function getTableList() {
                         _action_clicked_detail_collect: false,
                         _action_clicked_pushed: false,
                         _action_clicked_remove_history: false,
+                        _action_clicked_stop_download: false,
                         // _action_clicked_submit: false,
                     }
                 })
@@ -336,7 +341,7 @@ const addRecord = () => {
 
 const getActionCommonParams = row => {
     const param = {
-        recordId: row._id,
+        recordid: row._id,
         state: row.state
     }
     const other = {
@@ -453,7 +458,7 @@ const tableEvents = {
     },
     handleDetailCollect(index, row) {
         onlyClickHighlight(row, '_action_clicked_detail_collect')
-        const pass = row.state === 3 || row.state === 5
+        const pass = row.state === 3 || row.state === 5 || row.state === 6
         if (!pass) {
             return ElMessage({
                 message: '请先完成上一步操作!',
@@ -559,6 +564,36 @@ const tableEvents = {
           },
         })
     },
+    stopDownloadData(_, row) {
+      onlyClickHighlight(row, '_action_clicked_stop_download')
+      confirmDialog({
+        success: () => {
+          loading.value = true
+          const payload = {
+            recordid: row._id,
+          }
+          console.log("payload",payload)
+          QlmStopDownloadData(payload).then(r => {
+            if (r.err === 1) {
+              ElMessage({
+                message: '操作成功',
+                type: 'success',
+                duration: 3000,
+              })
+              getTableList()
+            } else {
+              return ElMessage({
+                message: r.msg || '操作失败',
+                type: 'error',
+                duration: 3000,
+              })
+            }
+          }).finally(() => {
+            loading.value = false
+          })
+        },
+      })
+    },
 }
 
 const showRecordInfoDialog = (type) => {

+ 59 - 17
frontend/src/views/ReviewList.vue

@@ -141,6 +141,23 @@
     <EditSpider ref="editSpiderDialog" @custom-event="dialogEvents.editSpiderConfigSaveEvent" @data-tag="editDialogMarkClick($event)" />
     <RunSpiderDialog ref="runSpiderDialog" />
     <VerifySpider ref="verifySpiderDialog" />
+    <el-dialog v-model="dialog.rollbackReason" title="选择退回原因" width="500">
+      <el-form>
+        <el-form-item label="退回原因">
+          <el-select v-model="filters.rollbackReason" placeholder="请选择">
+            <el-option v-for="item in filterConfig.rollbackOptions" :key="item.value" :label="item.label" :value="item.value" />
+          </el-select>
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button @click="dialog.rollbackReason = false">取消</el-button>
+          <el-button type="primary" @click="tableEvents.confirmRollbackReason(currentEditRow)">
+            确定
+          </el-button>
+        </div>
+      </template>
+    </el-dialog>
 </template>
 
 <script setup>
@@ -157,6 +174,7 @@ import VerifySpider from "../components/spider/VerifySpider.vue"
 import { useReviewListFiltersWithRole } from '../composables/filter-options'
 import { USER_ROLE_ADMIN, USER_ROLE_DEVELOPER, USER_ROLE_REVIEWER } from '../data/user'
 import { Refresh, Search, Box } from '@element-plus/icons-vue'
+import { rollbackReasonList } from "../data/index.js";
 
 const router = useRouter();
 const store = useStore();
@@ -177,7 +195,8 @@ const filterConfig = reactive({
             label: '全部',
             value: '-1',
         }
-    ]
+    ],
+    rollbackOptions: rollbackReasonList
 })
 
 
@@ -191,6 +210,7 @@ const defaultFilters = {
     modifyuser: '-1',
     // 认领状态
     claimtype: -1,
+    rollbackReason: undefined,
 }
 // 选择器数据
 const filters = reactive({
@@ -202,6 +222,7 @@ const filters = reactive({
     modifyuser: '-1',
     // 认领状态
     claimtype: -1,
+    rollbackReason: undefined,
 })
 
 // 列表数据
@@ -234,6 +255,10 @@ const defaultListState = {
     list: [],
 }
 
+const dialog = reactive({
+  rollbackReason: false
+})
+
 // 当前编辑的row的数据
 const currentEditRow = ref({})
 // 上一个点击的row的数据
@@ -693,7 +718,7 @@ const tableEvents = {
         const param = {
             stype: info.stype,
         }
-        
+
         ServerActionUpdateCodeState({ lua: luaArr, param }).then(r => {
             if (r.err === 1) {
                 ElMessage({
@@ -839,22 +864,39 @@ const tableEvents = {
     // 管理退回
     adminRollback(_, row) {
         onlyClickHighlight(row, '_action_clicked_rollback')
-        ElMessageBox.confirm('确认退回?', '提示',
-            {
-                customClass: 'j-confirm-message-box',
-                type: 'warning',
-                confirmButtonText: '确认',
-                cancelButtonText: '取消',
-                showCancelButton: false,
-            }
-        ).then(() => {
-            this.updateCodeStateAction([row], {
-                state: 12,
-                stype: '退回',
-                successTip: '退回成功',
-                errorTip: '退回失败',
-            })
+        currentEditRow.value = row
+        // ElMessageBox.confirm('确认退回?', '提示',
+        //     {
+        //         customClass: 'j-confirm-message-box',
+        //         type: 'warning',
+        //         confirmButtonText: '确认',
+        //         cancelButtonText: '取消',
+        //         showCancelButton: false,
+        //     }
+        // ).then(() => {
+        //     tableEvents.confirmAdminRollback(row)
+        // })
+        dialog.rollbackReason = true
+    },
+    confirmRollbackReason(row) {
+      if (!filters.rollbackReason) {
+        return ElMessage({
+          message: '请选择退回原因',
+          type: 'error',
+          duration: 3000,
         })
+      }
+      dialog.rollbackReason = false
+      tableEvents.confirmAdminRollback(row)
+    },
+    confirmAdminRollback: function (row) {
+      this.updateCodeStateAction([row], {
+        state: 12,
+        stype: '退回',
+        reason: filters.rollbackReason,
+        successTip: '退回成功',
+        errorTip: '退回失败',
+      })
     },
     // 管理员打回
     adminReject(_, row) {

+ 2 - 0
frontend/wailsjs/go/main/App.d.ts

@@ -40,6 +40,8 @@ export function QlmRunExportExcelFile(arg1:string,arg2:string):Promise<void>;
 
 export function QlmRunExportJsonFile(arg1:string,arg2:string):Promise<void>;
 
+export function QlmStopDownloadData(arg1:{[key: string]: any}):Promise<main.Result>;
+
 export function RunExportEpubFile(arg1:string,arg2:string,arg3:list.List):Promise<void>;
 
 export function RunExportExcelFile(arg1:string,arg2:string,arg3:list.List):Promise<void>;

+ 4 - 0
frontend/wailsjs/go/main/App.js

@@ -74,6 +74,10 @@ export function QlmRunExportJsonFile(arg1, arg2) {
   return window['go']['main']['App']['QlmRunExportJsonFile'](arg1, arg2);
 }
 
+export function QlmStopDownloadData(arg1) {
+  return window['go']['main']['App']['QlmStopDownloadData'](arg1);
+}
+
 export function RunExportEpubFile(arg1, arg2, arg3) {
   return window['go']['main']['App']['RunExportEpubFile'](arg1, arg2, arg3);
 }

+ 32 - 19
qianlima.go

@@ -14,6 +14,15 @@ import (
 	"time"
 )
 
+// QlmStopDownloadData 终止下载
+func (a *App) QlmStopDownloadData(record map[string]interface{}) *Result {
+	r := &Result{}
+	qu.Debug(record)
+	glvm.CloseTabs() //关闭浏览器资源
+	r.Err = 1
+	return r
+}
+
 // QlmListDataDownload 千里马列表页数据下载
 func (a *App) QlmListDataDownload(param map[string]interface{}, record map[string]interface{}) *Result {
 	qu.Debug(param, record)
@@ -23,10 +32,10 @@ func (a *App) QlmListDataDownload(param map[string]interface{}, record map[strin
 			page := "list"
 			detailScript := glvm.LoadScript("list")
 			if detailScript != "" {
-				//getResult(map[string]interface{}{"param": param, "user": User}, r, "qlm/updateRecord")
-				//if r.Err == 1 {
-				go DownloadData(record, detailScript, page) //下载
-				//}
+				getResult(map[string]interface{}{"param": param, "user": User}, r, "qlm/updateRecord")
+				if r.Err == 1 {
+					go DownloadData(record, detailScript, page) //下载
+				}
 			} else {
 				r.Msg = "详情页采集脚本加载失败!"
 			}
@@ -35,7 +44,6 @@ func (a *App) QlmListDataDownload(param map[string]interface{}, record map[strin
 		}
 	} else {
 		r.Msg = "用户登录异常,请重新登录!"
-		qu.Debug(r.Msg)
 	}
 	return r
 }
@@ -50,12 +58,12 @@ func (a *App) QlmDetailDataDownload(param map[string]interface{}, record map[str
 			detailScript := glvm.LoadScript("detail")
 			if detailScript != "" {
 				script.Datas = []map[string]interface{}{}
-				getData(nil, qu.ObjToString(record["recordId"]), "json", "download", &script.Datas)
+				getData(nil, qu.ObjToString(record["recordid"]), "json", "download", &script.Datas)
 				if len(script.Datas) > 0 {
 					r.Err = 1
 					go DownloadData(record, detailScript, page) //下载
 				} else {
-					r.Msg = "未获取到列表页数据!"
+					r.Msg = "无可采集数据!"
 				}
 				//getResult(map[string]interface{}{"param": param, "user": User}, r, "qlm/updateRecord")
 			} else {
@@ -80,18 +88,19 @@ func DownloadData(record map[string]interface{}, scriptText, page string) {
 	glvm.ProxyServer, _ = record["proxyServer"].(bool)
 	glvm.Headless, _ = record["headless"].(bool)
 	glvm.ShowImage, _ = record["showImage"].(bool)
-	recordId := qu.ObjToString(record["recordId"])
+	recordId := qu.ObjToString(record["recordid"])
 	//执行脚本
 	glvm.RunScript(scriptText, recordId)
 	for len(script.DataCache) > 0 {
+		qu.Debug("当前待保存数据量:", len(script.DataCache))
 		time.Sleep(time.Second * 1)
 	}
-	//state := 2
-	//if page == "detail" {
-	//	state = 5
-	//}
-	//r := &Result{}
-	//getResult(map[string]interface{}{"param": map[string]interface{}{"recordid": recordId, "state": state}}, r, "qlm/updateRecord")
+	state := 2
+	if page == "detail" {
+		state = 5
+	}
+	r := &Result{}
+	getResult(map[string]interface{}{"param": map[string]interface{}{"recordid": recordId, "state": state}}, r, "qlm/updateRecord")
 }
 
 // QlmRunExportExcelFile 导出excel
@@ -189,14 +198,18 @@ func getData(file *excelize.File, recordId, exportStype, from string, result *[]
 				file.SetCellStr("Sheet1", "A"+indexStr, qu.ObjToString(tmp["_id"]))
 				file.SetCellStr("Sheet1", "B"+indexStr, qu.ObjToString(tmp["title"]))
 				file.SetCellStr("Sheet1", "C"+indexStr, qu.ObjToString(tmp["href"]))
-				publishtime := qu.Int64All(tmp["publishtime"])
-				if publishtime == 0 {
-					file.SetCellStr("Sheet1", "D"+indexStr, "")
+				if ptime, ok := tmp["publishtime"].(string); ok {
+					file.SetCellStr("Sheet1", "D"+indexStr, ptime)
 				} else {
-					file.SetCellStr("Sheet1", "D"+indexStr, qu.FormatDateByInt64(&publishtime, qu.Date_Full_Layout))
+					publishtime := qu.Int64All(tmp["publishtime"])
+					if publishtime == 0 {
+						file.SetCellStr("Sheet1", "D"+indexStr, "")
+					} else {
+						file.SetCellStr("Sheet1", "D"+indexStr, qu.FormatDateByInt64(&publishtime, qu.Date_Full_Layout))
+					}
 				}
 				repeatText := ""
-				if repeat := tmp["repeat"]; repeat != nil {
+				if repeat := tmp["rp"]; repeat != nil {
 					if repeatTmp, ok := repeat.(bool); ok && repeatTmp {
 						repeatText = "重复"
 					} else {