├── icons ├── icon.icns ├── icon.png └── icon-256.png ├── preview └── task.png ├── public ├── .gitignore ├── public │ ├── favicon.ico │ ├── favicon.png │ └── favicon-256.png ├── src │ ├── assets │ │ └── style │ │ │ ├── variables.scss │ │ │ └── style.scss │ ├── store │ │ ├── index.js │ │ └── module │ │ │ ├── LorcaToJs.js │ │ │ ├── lorca.js │ │ │ └── tasks.js │ ├── components │ │ ├── base │ │ │ ├── SelTip.vue │ │ │ ├── MapEdit.vue │ │ │ └── ArrMapEdit.vue │ │ ├── taskModule │ │ │ ├── UnderDevelopment.vue │ │ │ ├── Navigate.vue │ │ │ ├── CaptureScreenshot.vue │ │ │ ├── AddReqHeaders.vue │ │ │ ├── Click.vue │ │ │ ├── WaitVisible.vue │ │ │ ├── Pdf.vue │ │ │ ├── Sleep.vue │ │ │ ├── SetValue.vue │ │ │ ├── EmulateViewport.vue │ │ │ ├── Evaluate.vue │ │ │ ├── Screenshot.vue │ │ │ └── AddCookies.vue │ │ ├── AppBar.vue │ │ ├── taskPanel │ │ │ ├── AddTaskPanel.vue │ │ │ ├── TaskCard.vue │ │ │ ├── EditTask.vue │ │ │ ├── EditSubTask.vue │ │ │ └── Tasks.vue │ │ └── Container.vue │ ├── main.js │ ├── App.vue │ ├── utils │ │ ├── common.js │ │ └── validateRules.js │ └── config │ │ └── tasks.js ├── vite.config.js ├── index.html ├── package.json ├── README.md └── yarn.lock ├── .gitattributes ├── config └── main.go ├── .gitignore ├── go.mod ├── js ├── eval.go └── bind.go ├── tasks ├── cookies.go ├── request.go ├── evaluate.go ├── parserRunTask.go ├── pdf.go ├── main.go ├── screenshot.go └── base.go ├── main.go ├── LICENSE ├── helper └── dir.go ├── README.md └── go.sum /icons/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xusenlin/cdp-ui/HEAD/icons/icon.icns -------------------------------------------------------------------------------- /icons/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xusenlin/cdp-ui/HEAD/icons/icon.png -------------------------------------------------------------------------------- /preview/task.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xusenlin/cdp-ui/HEAD/preview/task.png -------------------------------------------------------------------------------- /icons/icon-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xusenlin/cdp-ui/HEAD/icons/icon-256.png -------------------------------------------------------------------------------- /public/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | dist 4 | *.local 5 | package-lock.json -------------------------------------------------------------------------------- /public/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xusenlin/cdp-ui/HEAD/public/public/favicon.ico -------------------------------------------------------------------------------- /public/public/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xusenlin/cdp-ui/HEAD/public/public/favicon.png -------------------------------------------------------------------------------- /public/public/favicon-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xusenlin/cdp-ui/HEAD/public/public/favicon-256.png -------------------------------------------------------------------------------- /public/src/assets/style/variables.scss: -------------------------------------------------------------------------------- 1 | /* 改变主题色变量 */ 2 | $--color-primary: #2196f3; 3 | 4 | $--color-success: #67c23a; 5 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.js linguist-language=GoLang 2 | *.css linguist-language=GoLang 3 | *.html linguist-language=GoLang 4 | *.vue linguist-language=GoLang 5 | -------------------------------------------------------------------------------- /public/vite.config.js: -------------------------------------------------------------------------------- 1 | import vue from "@vitejs/plugin-vue"; 2 | 3 | /** 4 | * @type {import('vite').UserConfig} 5 | */ 6 | export default { 7 | plugins: [vue()] 8 | }; 9 | -------------------------------------------------------------------------------- /config/main.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import "os" 4 | 5 | var ResourcesDir string 6 | var TaskFile string 7 | 8 | func init() { 9 | 10 | currentDir, err := os.Getwd() 11 | if err != nil { 12 | panic(err) 13 | } 14 | ResourcesDir = currentDir + "/resources" 15 | TaskFile = currentDir + "/Task.json" 16 | } 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, built with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | 14 | .idea 15 | 16 | Task.json 17 | 18 | resources 19 | .DS_Store 20 | -------------------------------------------------------------------------------- /public/src/store/index.js: -------------------------------------------------------------------------------- 1 | import { createStore } from "vuex"; 2 | import tasks from "./module/tasks.js"; 3 | import lorca from "./module/lorca.js"; 4 | import "./module/LorcaToJs.js"; 5 | 6 | // Create a new store instance. 7 | export const store = createStore({ 8 | modules: { 9 | tasks, 10 | lorca 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /public/src/components/base/SelTip.vue: -------------------------------------------------------------------------------- 1 | 11 | -------------------------------------------------------------------------------- /public/src/main.js: -------------------------------------------------------------------------------- 1 | import { createApp } from "vue"; 2 | import App from "./App.vue"; 3 | import ElementPlus from "element-plus"; 4 | import { store } from "./store/index"; 5 | import "./assets/style/style.scss"; 6 | createApp(App) 7 | .use(store) 8 | .use(ElementPlus) 9 | .mount("#app"); 10 | 11 | store.dispatch("initTaskByJsonFile"); 12 | -------------------------------------------------------------------------------- /public/src/components/taskModule/UnderDevelopment.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 20 | -------------------------------------------------------------------------------- /public/src/store/module/LorcaToJs.js: -------------------------------------------------------------------------------- 1 | import { store } from "../index.js"; 2 | import { ElNotification } from "element-plus"; 3 | window.Notice = (message, type) => { 4 | ElNotification({ message, type, title: type.toUpperCase(), duration: 4000 }); 5 | }; 6 | 7 | window.UpdateProgress = (taskIndex, progress) => { 8 | store.commit("updateProgress", { taskIndex, progress }); 9 | }; 10 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Cdp_Ui 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /public/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cdpui", 3 | "version": "0.0.1", 4 | "scripts": { 5 | "dev": "vite", 6 | "build": "vite build" 7 | }, 8 | "dependencies": { 9 | "element-plus": "latest", 10 | "vue": "^3.0.5", 11 | "vuex": "^4.0.0" 12 | }, 13 | "devDependencies": { 14 | "@vitejs/plugin-vue": "^1.0.4", 15 | "@vue/compiler-sfc": "^3.0.5", 16 | "sass": "^1.32.8", 17 | "vite": "^2.0.0-beta.12" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /public/README.md: -------------------------------------------------------------------------------- 1 | # element-plus-vite-starter 2 | 3 | > A starter kit for Element Plus with Vite 4 | 5 | Element Plus 6 | 7 | 8 | ## Project setup 9 | ``` 10 | npm install 11 | ``` 12 | 13 | ### Compiles and hot-reloads for development 14 | ``` 15 | npm run dev 16 | ``` 17 | 18 | ### Compiles and minifies for production 19 | ``` 20 | npm run build 21 | ``` 22 | -------------------------------------------------------------------------------- /public/src/components/taskModule/Navigate.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 27 | -------------------------------------------------------------------------------- /public/src/components/taskModule/CaptureScreenshot.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 28 | -------------------------------------------------------------------------------- /public/src/components/taskModule/AddReqHeaders.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 27 | -------------------------------------------------------------------------------- /public/src/App.vue: -------------------------------------------------------------------------------- 1 | 5 | 6 | 14 | 15 | 26 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module cdpui 2 | 3 | go 1.16 4 | 5 | require ( 6 | github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef // indirect 7 | github.com/chromedp/cdproto v0.0.0-20210222063305-a3ac505ff0bd // indirect 8 | github.com/chromedp/chromedp v0.6.6 // indirect 9 | github.com/disintegration/imaging v1.6.0 // indirect 10 | github.com/gorilla/websocket v1.4.0 // indirect 11 | github.com/knq/sysutil v0.0.0-20181215143952-f05b59f0f307 // indirect 12 | github.com/mitchellh/mapstructure v1.4.1 // indirect 13 | github.com/zserge/lorca v0.1.9 14 | golang.org/x/image v0.0.0-20190417020941-4e30a6eb7d9a // indirect 15 | ) 16 | -------------------------------------------------------------------------------- /public/src/components/taskModule/Click.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 30 | -------------------------------------------------------------------------------- /js/eval.go: -------------------------------------------------------------------------------- 1 | package js 2 | 3 | 4 | import "fmt" 5 | 6 | func notice(s string, t string) string { 7 | return fmt.Sprintf("window.Notice(`%s`,`%s`)", s, t) 8 | } 9 | 10 | func notifySuccess(s string) string { 11 | return notice(s, "success") 12 | } 13 | func notifyWarning(s string) string { 14 | return notice(s, "warning") 15 | } 16 | func notifyInfo(s string) string { 17 | return notice(s, "info") 18 | } 19 | func notifyError(s string) string { 20 | return notice(s, "error") 21 | } 22 | 23 | func updateProgress(taskIndex int, progress int) string { 24 | return fmt.Sprintf(`window.UpdateProgress("%v","%v")`, taskIndex, progress) 25 | } -------------------------------------------------------------------------------- /public/src/components/taskModule/WaitVisible.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 30 | -------------------------------------------------------------------------------- /public/src/store/module/lorca.js: -------------------------------------------------------------------------------- 1 | import { clone } from "../../utils/common.js"; 2 | export default { 3 | state() { 4 | return {}; 5 | }, 6 | mutations: { 7 | runTask(state, val) { 8 | let { index, task } = val; 9 | let t = clone(task); 10 | t.index = index; 11 | window.RunTask(JSON.stringify(t)); 12 | }, 13 | stopTask(state, index) { 14 | window.StopTask(JSON.stringify(index)); 15 | }, 16 | openFile(state, index) { 17 | window.OpenFile(JSON.stringify(index)); 18 | }, 19 | saveJsonFile(state, tasks) { 20 | window.SaveJsonFile(JSON.stringify(tasks)); 21 | } 22 | } 23 | }; 24 | -------------------------------------------------------------------------------- /public/src/components/taskModule/Pdf.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 30 | -------------------------------------------------------------------------------- /public/src/components/taskModule/Sleep.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 33 | -------------------------------------------------------------------------------- /tasks/cookies.go: -------------------------------------------------------------------------------- 1 | package tasks 2 | 3 | import ( 4 | "errors" 5 | "github.com/asaskevich/govalidator" 6 | "github.com/chromedp/cdproto/network" 7 | "github.com/chromedp/chromedp" 8 | "github.com/mitchellh/mapstructure" 9 | ) 10 | 11 | func (t *Task) addCookies(args taskArgs) error { 12 | var expectArgs struct { 13 | Cookies []*network.CookieParam `valid:"-"` 14 | } 15 | 16 | if err := mapstructure.Decode(args, &expectArgs); err != nil { 17 | return errors.New("addCookies子任务出错:" + err.Error()) 18 | } 19 | 20 | if _, err := govalidator.ValidateStruct(&expectArgs); err != nil { 21 | return errors.New("addCookies子任务参数出错:" + err.Error()) 22 | } 23 | return chromedp.Run(*t.ctx, network.SetCookies(expectArgs.Cookies), ) 24 | } 25 | -------------------------------------------------------------------------------- /tasks/request.go: -------------------------------------------------------------------------------- 1 | package tasks 2 | 3 | import ( 4 | "errors" 5 | "github.com/asaskevich/govalidator" 6 | "github.com/chromedp/cdproto/network" 7 | "github.com/chromedp/chromedp" 8 | "github.com/mitchellh/mapstructure" 9 | ) 10 | 11 | func (t *Task) addReqHeaders(args taskArgs) error { 12 | var expectArgs struct { 13 | Headers taskArgs `valid:"-"` 14 | } 15 | 16 | if err := mapstructure.Decode(args, &expectArgs); err != nil { 17 | return errors.New("setReqHeaders子任务出错:" + err.Error()) 18 | } 19 | if _, err := govalidator.ValidateStruct(&expectArgs); err != nil { 20 | return errors.New("setReqHeaders子任务参数出错:" + err.Error()) 21 | } 22 | return chromedp.Run(*t.ctx, 23 | network.Enable(), 24 | network.SetExtraHTTPHeaders(network.Headers(expectArgs.Headers)), 25 | ) 26 | } 27 | -------------------------------------------------------------------------------- /public/src/components/taskModule/SetValue.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 37 | -------------------------------------------------------------------------------- /public/src/components/taskModule/EmulateViewport.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 27 | 34 | -------------------------------------------------------------------------------- /public/src/assets/style/style.scss: -------------------------------------------------------------------------------- 1 | @import "./variables.scss"; 2 | 3 | /* 改变 icon 字体路径变量,必需 */ 4 | $--font-path: "element-plus/lib/theme-chalk/fonts"; 5 | 6 | @import "element-plus/packages/theme-chalk/src/index"; 7 | 8 | * { 9 | padding: 0; 10 | margin: 0; 11 | box-sizing: border-box; 12 | } 13 | 14 | ::-webkit-scrollbar { 15 | width: 6px; 16 | height: 6px; 17 | background-color: #f7f7f7; 18 | } 19 | ::-webkit-scrollbar-thumb { 20 | -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3); 21 | background-color: $--color-primary; 22 | } 23 | // 24 | //.terminal { 25 | // max-width: 600px; 26 | // padding: 10px; 27 | // max-height: 60vh; 28 | // overflow-y: auto; 29 | // white-space: pre-wrap; 30 | // &::-webkit-scrollbar { 31 | // display: none; 32 | // } 33 | //} 34 | 35 | .el-progress-bar__outer { 36 | background-color: #dcdfe6; 37 | } 38 | -------------------------------------------------------------------------------- /public/src/components/taskModule/Evaluate.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 40 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "cdpui/js" 5 | "fmt" 6 | "github.com/zserge/lorca" 7 | "runtime" 8 | ) 9 | 10 | 11 | 12 | func main() { 13 | var args []string 14 | if runtime.GOOS == "linux" { 15 | args = append(args, "--class=Lorca") 16 | } 17 | 18 | ui, err := lorca.New("", "", 1376, 900, args...) 19 | if err != nil { 20 | fmt.Println(err) 21 | return 22 | } 23 | defer ui.Close() 24 | 25 | if err := js.Bind(&ui); err != nil { 26 | fmt.Println(err) 27 | return 28 | } 29 | 30 | //ln, err := net.Listen("tcp", "127.0.0.1:0") 31 | //if err != nil { 32 | // fmt.Println(err) 33 | //} 34 | //defer ln.Close() 35 | // 36 | //go http.Serve(ln, http.FileServer(http.Dir("public/dist"))) 37 | //err = ui.Load(fmt.Sprintf("http://%s", ln.Addr())) 38 | err = ui.Load("http://192.168.50.171:3000/") 39 | if err != nil { 40 | fmt.Println(err) 41 | } 42 | 43 | <-ui.Done() 44 | } 45 | -------------------------------------------------------------------------------- /tasks/evaluate.go: -------------------------------------------------------------------------------- 1 | package tasks 2 | 3 | import ( 4 | "errors" 5 | "github.com/asaskevich/govalidator" 6 | "github.com/chromedp/chromedp" 7 | "github.com/mitchellh/mapstructure" 8 | "io/ioutil" 9 | ) 10 | 11 | func (t *Task) evaluate(args taskArgs) error { 12 | var expectArgs struct { 13 | Script string `valid:"required"` 14 | FileName string `valid:"required"` 15 | } 16 | if err := mapstructure.Decode(args, &expectArgs); err != nil { 17 | return errors.New("evaluate子任务出错:" + err.Error()) 18 | } 19 | 20 | if _, err := govalidator.ValidateStruct(&expectArgs); err != nil { 21 | return errors.New("evaluate子任务参数出错:" + err.Error()) 22 | } 23 | 24 | var file []byte 25 | err := chromedp.Run(*t.ctx, chromedp.Evaluate(expectArgs.Script, &file)) 26 | 27 | if err != nil { 28 | return errors.New("evaluate子任务出错:" + err.Error()) 29 | } 30 | if err := ioutil.WriteFile(t.workDir()+"/"+expectArgs.FileName, file, 0666); err != nil { 31 | return err 32 | } 33 | 34 | return nil 35 | } 36 | -------------------------------------------------------------------------------- /public/src/components/taskModule/Screenshot.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 46 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 SenLin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /public/src/components/AppBar.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 27 | 28 | 49 | -------------------------------------------------------------------------------- /public/src/components/taskPanel/AddTaskPanel.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 23 | 24 | 58 | -------------------------------------------------------------------------------- /tasks/parserRunTask.go: -------------------------------------------------------------------------------- 1 | package tasks 2 | 3 | import "errors" 4 | 5 | func (t *Task) parserRun() error { 6 | for progress, task := range t.Tasks { 7 | t.progress = progress 8 | t.callBack(progress) 9 | if err := t.selectFunc(task.Name, task.Args); err != nil { 10 | return err 11 | } 12 | } 13 | return nil 14 | } 15 | 16 | func (t *Task) selectFunc(taskName string, taskArgs taskArgs) error { 17 | switch taskName { 18 | case "pdf": 19 | return t.pdf(taskArgs) 20 | case "click": 21 | return t.click(taskArgs) 22 | case "sleep": 23 | return t.sleep(taskArgs) 24 | case "evaluate": 25 | return t.evaluate(taskArgs) 26 | case "navigate": 27 | return t.navigate(taskArgs) 28 | case "setValue": 29 | return t.setValue(taskArgs) 30 | case "screenshot": 31 | return t.screenshot(taskArgs) 32 | case "addCookies": 33 | return t.addCookies(taskArgs) 34 | case "waitVisible": 35 | return t.waitVisible(taskArgs) 36 | case "addReqHeaders": 37 | return t.addReqHeaders(taskArgs) 38 | case "emulateViewport": 39 | return t.emulateViewport(taskArgs) 40 | case "captureScreenshot": 41 | return t.captureScreenshot(taskArgs) 42 | default: 43 | return errors.New("未识别的任务名字" + taskName) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /helper/dir.go: -------------------------------------------------------------------------------- 1 | package helper 2 | 3 | import ( 4 | "cdpui/config" 5 | "fmt" 6 | "os" 7 | "os/exec" 8 | "strings" 9 | ) 10 | 11 | func IsDir(name string) bool { 12 | if info, err := os.Stat(name); err == nil { 13 | return info.IsDir() 14 | } 15 | return false 16 | } 17 | 18 | func FileIsExisted(filename string) bool { 19 | existed := true 20 | if _, err := os.Stat(filename); os.IsNotExist(err) { 21 | existed = false 22 | } 23 | return existed 24 | } 25 | 26 | func MakeDir(dir string) error { 27 | if !IsDir(dir) { 28 | return os.MkdirAll(dir, os.ModePerm) 29 | } 30 | return nil 31 | } 32 | 33 | func RemoveFile(file string) error { 34 | if FileIsExisted(file) { 35 | return os.Remove(file) 36 | } 37 | return nil 38 | } 39 | 40 | func RemoveDir(dir string) error { 41 | if IsDir(dir) { 42 | return os.RemoveAll(dir) 43 | } 44 | return nil 45 | } 46 | 47 | func GetWorkDir(index int) string { 48 | return fmt.Sprintf("%s/%v_task", config.ResourcesDir, index) 49 | } 50 | 51 | func OpenFileManager(index int) error { 52 | //TODO mac linux OpenFileManager Implement 53 | dir := strings.ReplaceAll(GetWorkDir(index),"/","\\") 54 | cmd := exec.Command(`explorer.exe`, `select,`, dir) 55 | return cmd.Run() 56 | } 57 | -------------------------------------------------------------------------------- /tasks/pdf.go: -------------------------------------------------------------------------------- 1 | package tasks 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "github.com/asaskevich/govalidator" 7 | "github.com/chromedp/cdproto/page" 8 | "github.com/chromedp/chromedp" 9 | "github.com/mitchellh/mapstructure" 10 | "io/ioutil" 11 | ) 12 | 13 | func (t *Task) pdf(args taskArgs) error { 14 | 15 | if t.ShowBrowser { 16 | return errors.New("打印网页PDF只支持在无头浏览器模式下运行") 17 | } 18 | 19 | var expectArgs struct { 20 | FileName string `valid:"required"` 21 | } 22 | if err := mapstructure.Decode(args, &expectArgs); err != nil { 23 | return errors.New("pdf子任务出错:" + err.Error()) 24 | } 25 | 26 | if _, err := govalidator.ValidateStruct(&expectArgs); err != nil { 27 | return errors.New("pdf子任务参数出错:" + err.Error()) 28 | } 29 | 30 | var res []byte 31 | err := chromedp.Run(*t.ctx, 32 | chromedp.ActionFunc(func(ctx context.Context) error { 33 | buf, _, err := page.PrintToPDF().WithPrintBackground(false).Do(ctx) 34 | if err != nil { 35 | return err 36 | } 37 | res = buf 38 | return nil 39 | }), 40 | ) 41 | if err != nil { 42 | return errors.New("pdf子任务出错(必须是无头浏览器才能正常运行):" + err.Error()) 43 | } 44 | if err := ioutil.WriteFile(t.workDir()+"/"+expectArgs.FileName, res, 0666); err != nil { 45 | return err 46 | } 47 | 48 | return nil 49 | } 50 | -------------------------------------------------------------------------------- /public/src/utils/common.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 重置对象参数 3 | * @params -> Object 4 | * @arg = Array => [] 5 | * @arg = Boolean => false 6 | * @arg = Number => null 7 | * @arg = String => '' 8 | * */ 9 | export function resetArgs(args, def = {}) { 10 | for (let key in args) { 11 | console.log(key); 12 | if (def.hasOwnProperty(key)) { 13 | args[key] = def[key]; 14 | } else { 15 | if (Array.isArray(args[key])) { 16 | args[key] = []; 17 | } 18 | if ("string" == typeof args[key]) { 19 | args[key] = ""; 20 | } 21 | if ("number" == typeof args[key]) { 22 | args[key] = null; 23 | } 24 | if ("boolean" == typeof args[key]) { 25 | args[key] = false; 26 | } 27 | if (Object.prototype.toString.call(args[key]) === "[object Object]") { 28 | args[key] = {}; 29 | } 30 | } 31 | } 32 | } 33 | 34 | /** 35 | * 填充对象属性 36 | * @param obj 37 | * @param row 38 | * row属性赋值到obj 39 | */ 40 | export function fillerLeft(obj, row = {}) { 41 | for (let key in obj) { 42 | if ( 43 | row.hasOwnProperty(key) && 44 | row[key] !== null && 45 | row[key] !== undefined 46 | ) { 47 | obj[key] = row[key]; 48 | } 49 | } 50 | } 51 | export function clone(obj) { 52 | return JSON.parse(JSON.stringify(obj)); 53 | } 54 | -------------------------------------------------------------------------------- /public/src/store/module/tasks.js: -------------------------------------------------------------------------------- 1 | import { ElNotification } from "element-plus"; 2 | 3 | export default { 4 | state() { 5 | return []; 6 | }, 7 | mutations: { 8 | addTask(state, task) { 9 | state.push(task); 10 | }, 11 | editTask(state, val) { 12 | let { task, index } = val; 13 | state[index] = task; 14 | }, 15 | delTask(state, index) { 16 | state.splice(index, 1); 17 | }, 18 | addSubTask(state, val) { 19 | let { task, parentIndex } = val; 20 | 21 | state[parentIndex].tasks.push(task); 22 | }, 23 | editSubTask(state, val) { 24 | let { task, parentIndex, index } = val; 25 | state[parentIndex].tasks[index] = task; 26 | }, 27 | delSubTask(state, val) { 28 | let { parentIndex, index } = val; 29 | state[parentIndex].tasks.splice(index, 1); 30 | }, 31 | updateProgress(state, val) { 32 | let { taskIndex, progress } = val; 33 | state[taskIndex].progress = parseInt(progress); 34 | }, 35 | initTask(state, t) { 36 | state.push(...t); 37 | } 38 | }, 39 | actions: { 40 | initTaskByJsonFile({ commit }) { 41 | if (!window.hasOwnProperty("GetJsonTask")) { 42 | commit("initTask", []); 43 | return; 44 | } 45 | window 46 | .GetJsonTask() 47 | .then(r => { 48 | let task = JSON.parse(r); 49 | 50 | commit("initTask", task || []); 51 | }) 52 | .catch(e => { 53 | ElNotification({ 54 | message: JSON.stringify(e), 55 | type: "error", 56 | title: "json 初始化任务出错", 57 | duration: 4000 58 | }); 59 | commit("initTask", []); 60 | }); 61 | } 62 | } 63 | }; 64 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Cdp_Ui 2 | 3 | #### 介绍 4 | CdpUI 是跨平台的,是一个使用 Golang 创建的本地实验性软件,可以构建一些子任务来控制浏览器做任何事情, 5 | 当然也可以通过少许改造变成一个 web 服务来供用户运行任务。 6 | 7 | ![Task](preview/task.png) 8 | 9 | 10 | 我希望 CdpUI 最终可以通过构建任务完成一些重复性的工作,例如: 11 | 12 | - 前端页面的自动化测试和性能报告(例如测试网页在不同窗口大小下的响应和适配效果) 13 | - 动态爬虫(任务依赖于浏览器渲染,理论上任何反爬虫措施都是无效的) 14 | - 基于网页的重复性工作自动化(例如重复性的通过网页数据来整理你的文档和表格) 15 | - ... 16 | 17 | 目前一些基本的工作已经完成,但是还有很多很棒的想法需要去完成。 18 | 19 | - [x] pdf || 生成PDF 20 | - [x] click || 点击元素 21 | - [x] sleep || 等待一会 22 | - [x] evaluate || 执行脚本 23 | - [x] navigate || 打开网址 24 | - [x] setValue || 往输入框输入内容 25 | - [x] screenshot || 截取网页内容 26 | - [x] addCookies || 添加Cookies 27 | - [x] waitVisible || 等待元素加载完成 28 | - [x] addReqHeaders || 添加请求头 29 | - [x] emulateViewport || 改变窗口大小 30 | - [x] captureScreenshot || 捕获屏幕 31 | - [ ] collectDataByExcel || 通过表格搜集数据 32 | - [ ] collectDataByWord || 通过文档搜集数据 33 | - [ ] packageFile || 打包目前生成的所有文件 34 | - [ ] ... 35 | 36 | 37 | 38 | #### 运行原理 39 | 40 | 借助第三方库,运行此程序会尝试找到本地安装的 Chrome 并打开一个 Chrome 窗口,通过websocket连接到其dev-tools端点, 41 | 发送要加载的HTML,并提供Go和JS之间的通信。基于此,前端通过 vue3 vite vuex 等提供页面 UI 和交互,通过将构建的任务发送到 Golang。 42 | 此时, Golang 会创建 Chrome 实例上下文,使用 Chrome DevTools 协议驱动无头浏览器(默认情况下无UI,你也可以显示浏览器以便查看任务的运行过程)来运行你组建的任务。 43 | 44 | 45 | #### 一些思考 46 | 通过表格搜集数据和通过文档搜集数据是什么呢?? 47 | 我在上一家公司曾经开发过一个功能,公司是一个集团子公司,按照集团要求,每个员工需要在一个月内学习一些东西并写出自己的读后感, 48 | HR需要收集每个人的读后感并整理成规定的word文档(对word的段落文字颜色大小有严格的规定)上交,这对于HR无疑是一个不小的挑战。 49 | 后来我提出在公司的OA办公系统里加入此功能,员工登陆系统提交自己的读后感,通过PHP读取预设的word文档模板,使用正则替换,一篇篇漂亮的文档就被生成了。 50 | 因此,通过文档收集网页数据就是这种思路,由你做好文档模板,精心排版,不过关键的地方需要你使用诸如${#app > div.body > div.main > div.paragraph }的符号表示, 51 | 那么在任务运行的过程中会将定位到的文字嵌入相应的地方,并且不会破坏你的文档格式。 52 | 53 | 虽然上面的这些功能最终都能被实现,但是对于自动化依旧有很大的局限性,除非给任务加入循环判断跳转的逻辑单元,否则它仅仅只能满足一部分场景,灵活度很有限。 54 | 但是,加入这些逻辑单元也会带来一些问题,比如一次运行任务可以简单将各种产生的文件生成,如果存在循环,那么文件名则需要处理以防止被覆盖等,因此此项目还在探索阶段,目前对于小白不是那么友好。 55 | -------------------------------------------------------------------------------- /public/src/components/base/MapEdit.vue: -------------------------------------------------------------------------------- 1 | 34 | 35 | 73 | 74 | 88 | -------------------------------------------------------------------------------- /public/src/components/Container.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 62 | 63 | 76 | -------------------------------------------------------------------------------- /public/src/components/base/ArrMapEdit.vue: -------------------------------------------------------------------------------- 1 | 34 | 35 | 80 | 81 | 95 | -------------------------------------------------------------------------------- /public/src/config/tasks.js: -------------------------------------------------------------------------------- 1 | import Pdf from "../components/taskModule/Pdf.vue"; 2 | import Click from "../components/taskModule/Click.vue"; 3 | import Sleep from "../components/taskModule/Sleep.vue"; 4 | import Evaluate from "../components/taskModule/Evaluate.vue"; 5 | import Navigate from "../components/taskModule/Navigate.vue"; 6 | import SetValue from "../components/taskModule/SetValue.vue"; 7 | import Screenshot from "../components/taskModule/Screenshot.vue"; 8 | import AddCookies from "../components/taskModule/AddCookies.vue"; 9 | import WaitVisible from "../components/taskModule/WaitVisible.vue"; 10 | import AddReqHeaders from "../components/taskModule/AddReqHeaders.vue"; 11 | import EmulateViewport from "../components/taskModule/EmulateViewport.vue"; 12 | import CaptureScreenshot from "../components/taskModule/CaptureScreenshot.vue"; 13 | import UnderDevelopment from "../components/taskModule/UnderDevelopment.vue"; 14 | export default [ 15 | { 16 | name: "pdf", 17 | title: "生成PDF", 18 | argsModule: Pdf 19 | }, 20 | { 21 | name: "click", 22 | title: "点击元素", 23 | argsModule: Click 24 | }, 25 | { 26 | name: "sleep", 27 | title: "等待一会", 28 | argsModule: Sleep 29 | }, 30 | { 31 | name: "evaluate", 32 | title: "执行脚本", 33 | argsModule: Evaluate 34 | }, 35 | { 36 | name: "navigate", 37 | title: "打开网址", 38 | argsModule: Navigate 39 | }, 40 | { 41 | name: "setValue", 42 | title: "往输入框输入内容", 43 | argsModule: SetValue 44 | }, 45 | { 46 | name: "screenshot", 47 | title: "截取网页内容", 48 | argsModule: Screenshot 49 | }, 50 | { 51 | name: "addCookies", 52 | title: "添加Cookies", 53 | argsModule: AddCookies 54 | }, 55 | { 56 | name: "waitVisible", 57 | title: "等待元素加载完成", 58 | argsModule: WaitVisible 59 | }, 60 | { 61 | name: "addReqHeaders", 62 | title: "添加请求头", 63 | argsModule: AddReqHeaders 64 | }, 65 | { 66 | name: "emulateViewport", 67 | title: "改变窗口大小", 68 | argsModule: EmulateViewport 69 | }, 70 | { 71 | name: "captureScreenshot", 72 | title: "捕获屏幕", 73 | argsModule: CaptureScreenshot 74 | }, 75 | { 76 | name: "collectDataByExcel", 77 | title: "通过表格搜集数据", 78 | argsModule: UnderDevelopment 79 | }, 80 | { 81 | name: "collectDataByWord", 82 | title: "通过文档搜集数据", 83 | argsModule: UnderDevelopment 84 | }, 85 | { 86 | name: "packageFile", 87 | title: "打包目前生成的所有文件", 88 | argsModule: UnderDevelopment 89 | } 90 | ]; 91 | -------------------------------------------------------------------------------- /public/src/utils/validateRules.js: -------------------------------------------------------------------------------- 1 | export const Phone = { 2 | pattern: /^1((3[\d])|(4[5,6,7,9])|(5[0-3,5-9])|(6[5-7])|(7[0-8])|(8[\d])|(9[1,8,9]))\d{8}$/, 3 | message: "请输入正确的手机号码", 4 | trigger: "blur" 5 | }; 6 | 7 | export const Number = { 8 | type: "number", 9 | message: "只能填写数字", 10 | trigger: "blur" 11 | }; 12 | 13 | export const String = { 14 | type: "string", 15 | message: "只能填写字符串", 16 | trigger: "blur" 17 | }; 18 | 19 | export const Required = { 20 | required: true, 21 | message: "填写不能为空", 22 | trigger: "blur" 23 | }; 24 | 25 | export const Array = { 26 | type: "array", 27 | message: "请选择选项", 28 | trigger: "change" 29 | }; 30 | 31 | export const Date = { type: "date", message: "请选择日期", trigger: "change" }; 32 | 33 | export const Email = { 34 | type: "email", 35 | message: "请输入正确的邮箱", 36 | trigger: "blur" 37 | }; 38 | 39 | export const StrLen3To18 = { 40 | pattern: /^.{3,18}$/, 41 | message: "字符长度限制在2到18个", 42 | trigger: "blur" 43 | }; 44 | 45 | export const Float = { 46 | pattern: /^(([1-9][0-9]*)|(([0]\.\d{1,2}|[1-9][0-9]*\.\d{1,2})))$/, 47 | message: "只能填写数字并且最多两位小数", 48 | trigger: "blur" 49 | }; 50 | 51 | export const FloatAnd0 = { 52 | pattern: /(^[1-9]([0-9]+)?(\.[0-9]{1,2})?$)|(^(0){1}$)|(^[0-9]\.[0-9]([0-9])?$)/, 53 | message: "只能填写数字并且最多两位小数", 54 | trigger: "blur" 55 | }; 56 | 57 | export const FloatGeq1 = { 58 | pattern: /(^[1-9]([0-9]+)?(\.[0-9]{1,2})?$)|(^[1-9]\.[0-9]([0-9])?$)/, 59 | message: "只能填写数字并且大于等于1,最多两位小数", 60 | trigger: "blur" 61 | }; 62 | 63 | export const FloatMax100 = { 64 | pattern: /^\d\.([1-9]{1,2}|[0-9][1-9])$|^[1-9]\d{0,1}(\.\d{1,2}){0,1}$|^100(\.0{1,2}){0,1}$/, 65 | message: "只能填写数字并且最大数是100不能超个两位小数", 66 | trigger: "blur" 67 | }; 68 | 69 | export const Url = { 70 | pattern: /(^https?|^nurse):\/\//i, 71 | message: "请输入正确的链接地址", 72 | trigger: "blur" 73 | }; 74 | 75 | export const IntMax99 = { 76 | pattern: /^[1-9][0-9]{0,1}$/, 77 | message: "只能填写1-99的整数", 78 | trigger: "blur" 79 | }; 80 | 81 | export const FloatMin0Max100 = { 82 | pattern: /^(\d|[1-9]\d|100)(\.\d{1,2})?$/, 83 | message: "只能填写0-100,不能超个两位小数", 84 | trigger: "blur" 85 | }; 86 | 87 | export const StrongPassword = { 88 | pattern: /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{6,18}$/, 89 | message: "大小写+数字组成,字数6-18位", 90 | trigger: "blur" 91 | }; 92 | 93 | export const NumberString = { 94 | pattern: /^\d+$/, 95 | message: "只能输入数字", 96 | trigger: "blur" 97 | }; 98 | 99 | export const Geq1NumberString = { 100 | pattern: /^[1-9][0-9]*$/, 101 | message: "只能填写大于等于1的整数", 102 | trigger: "blur" 103 | }; 104 | 105 | export const PasswordLength = { 106 | pattern: /^[0-9a-zA-Z]{8,20}$/, 107 | message: "数字或字母组成,字数8-20位", 108 | trigger: "blur" 109 | }; 110 | 111 | export function FillerFieldRules(fields = [], rules) { 112 | let newRules = {}; 113 | fields.forEach(f => { 114 | newRules[f] = rules; 115 | }); 116 | return newRules; 117 | } 118 | -------------------------------------------------------------------------------- /public/src/components/taskModule/AddCookies.vue: -------------------------------------------------------------------------------- 1 | 46 | 47 | 103 | 120 | -------------------------------------------------------------------------------- /tasks/main.go: -------------------------------------------------------------------------------- 1 | package tasks 2 | 3 | import ( 4 | "cdpui/helper" 5 | "context" 6 | "encoding/json" 7 | "errors" 8 | "github.com/chromedp/chromedp" 9 | "time" 10 | ) 11 | 12 | type taskArgs map[string]interface{} 13 | type flagArgs map[string]interface{} 14 | 15 | type Task struct { 16 | Index int `json:"index"` 17 | Title string `json:"title"` 18 | Tasks []taskDesc `json:"tasks"` 19 | Flags []flagArgs `json:"flags"` 20 | Width int `json:"width"` 21 | Height int `json:"height"` 22 | TimeOut time.Duration `json:"timeOut"` 23 | UserAgent string `json:"userAgent"` 24 | ShowBrowser bool `json:"showBrowser"` 25 | ////// 26 | progress int 27 | callBack func(int) 28 | ctx *context.Context 29 | cancel context.CancelFunc 30 | } 31 | 32 | type taskDesc struct { 33 | Name string `json:"name"` 34 | Args taskArgs `json:"args"` 35 | } 36 | 37 | func New(tasksDesc []byte) (*Task, error) { 38 | var task Task 39 | 40 | if err := json.Unmarshal(tasksDesc, &task); err != nil { 41 | return nil, errors.New("任务Json解析出错:" + err.Error()) 42 | } 43 | 44 | if task.Width == 0 { 45 | task.Width = 1366 46 | } 47 | if task.Height == 0 { 48 | task.Height = 768 49 | } 50 | if task.UserAgent == "" { 51 | task.UserAgent = `Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36` 52 | } 53 | 54 | return &task, nil 55 | } 56 | 57 | //目前还不支持操作打开新的TAB 58 | 59 | func (t *Task) Run() error { 60 | 61 | if err := t.initDir(); err != nil { 62 | return err 63 | } 64 | 65 | options := []chromedp.ExecAllocatorOption{ 66 | chromedp.Flag("headless", !t.ShowBrowser), 67 | chromedp.WindowSize(t.Width, t.Width), 68 | chromedp.UserAgent(t.UserAgent), 69 | 70 | } 71 | //chromedp.Flag("hide-scrollbars", false), 72 | //chromedp.Flag("mute-audio", false), 73 | //chromedp.Flag("mute-audio", false), 74 | //chromedp.Flag("ignore-certificate-errors", "1"), 75 | for k, v := range t.Flags { 76 | options = append(options, chromedp.Flag(string(k), v)) 77 | } 78 | 79 | options = append(chromedp.DefaultExecAllocatorOptions[:], options...) 80 | 81 | c, cc := chromedp.NewExecAllocator(context.Background(), options...) 82 | defer cc() 83 | 84 | ctx, cancel := chromedp.NewContext(c,chromedp.WithLogf(func(s string, i ...interface{}) { 85 | 86 | })) 87 | defer cancel() 88 | 89 | ctx, cancel = context.WithTimeout(ctx, t.TimeOut*time.Second) 90 | defer cancel() 91 | 92 | t.ctx = &ctx 93 | t.cancel = cc 94 | 95 | return t.parserRun() 96 | } 97 | 98 | func (t *Task) BindCallBack(f func(int)) { 99 | t.callBack = f 100 | } 101 | 102 | func (t *Task) Done() <-chan struct{} { 103 | return (*t.ctx).Done() 104 | } 105 | func (t *Task) Cancel() { 106 | t.cancel() 107 | } 108 | func (t *Task) workDir() string { 109 | return helper.GetWorkDir(t.Index) 110 | } 111 | 112 | func (t *Task) initDir() error { 113 | 114 | dir := t.workDir() 115 | 116 | if err := helper.RemoveDir(dir); err != nil { 117 | return err 118 | } 119 | 120 | if err := helper.MakeDir(dir); err != nil { 121 | return err 122 | } 123 | 124 | return nil 125 | } 126 | -------------------------------------------------------------------------------- /js/bind.go: -------------------------------------------------------------------------------- 1 | package js 2 | 3 | import ( 4 | "cdpui/config" 5 | "cdpui/helper" 6 | "cdpui/tasks" 7 | "github.com/zserge/lorca" 8 | "io/ioutil" 9 | "os" 10 | "strconv" 11 | ) 12 | var UI lorca.UI 13 | var Tasks = make(map[int]*tasks.Task) //正在运行的任务 14 | 15 | func Bind(ui *lorca.UI) error { 16 | UI = *ui 17 | if err := UI.Bind("RunTask", runTask); err != nil { 18 | return err 19 | } 20 | if err := UI.Bind("StopTask", stopTask); err != nil { 21 | return err 22 | } 23 | if err := UI.Bind("OpenFile", openFile); err != nil { 24 | return err 25 | } 26 | if err := UI.Bind("SaveJsonFile", saveJsonFile); err != nil { 27 | return err 28 | } 29 | if err := UI.Bind("GetJsonTask", getJsonTask); err != nil { 30 | return err 31 | } 32 | return nil 33 | } 34 | 35 | func runTask(t string) { 36 | task, err := tasks.New([]byte(t)) 37 | if err != nil { 38 | UI.Eval(notifyError(err.Error())) 39 | return 40 | } 41 | _, exist := Tasks[task.Index] 42 | if exist { 43 | UI.Eval(notifyError("之前的任务还在运行")) 44 | return 45 | } 46 | 47 | task.BindCallBack(func(progress int) { 48 | UI.Eval(updateProgress(task.Index, progress)) 49 | }) 50 | Tasks[task.Index] = task 51 | 52 | go func() { 53 | UI.Eval(notifyInfo("开始执行任务" + task.Title)) 54 | err = Tasks[task.Index].Run() 55 | if err != nil { 56 | UI.Eval(notifyError(err.Error())) 57 | UI.Eval(updateProgress(task.Index, -1)) 58 | delete(Tasks, task.Index) 59 | return 60 | } 61 | UI.Eval(notifySuccess("任务执行完毕")) 62 | UI.Eval(updateProgress(task.Index, -1)) 63 | delete(Tasks, task.Index) 64 | }() 65 | } 66 | 67 | func stopTask(i string) { 68 | index, err := strconv.Atoi(i) 69 | if err != nil { 70 | UI.Eval(notifyError(err.Error())) 71 | return 72 | } 73 | task, exist := Tasks[index] 74 | 75 | if !exist { 76 | UI.Eval(notifyError("此任务不存在")) 77 | return 78 | } 79 | select { 80 | case <-task.Done(): 81 | UI.Eval(updateProgress(task.Index, -1)) 82 | UI.Eval(notifySuccess("此任务已经完成")) 83 | default: 84 | task.Cancel() 85 | UI.Eval(updateProgress(task.Index, -1)) 86 | UI.Eval(notifySuccess("此任务已经暂停")) 87 | } 88 | } 89 | 90 | func openFile(i string) { 91 | index, err := strconv.Atoi(i) 92 | 93 | if err != nil { 94 | UI.Eval(notifyError(err.Error())) 95 | return 96 | } 97 | 98 | if !helper.IsDir(helper.GetWorkDir(index)) { 99 | UI.Eval(notifyWarning("此任务还没有产生文件")) 100 | return 101 | } 102 | 103 | if err := helper.OpenFileManager(index); err != nil { 104 | UI.Eval(notifyError(err.Error())) 105 | return 106 | } 107 | } 108 | 109 | func saveJsonFile(t string) { 110 | if err := helper.RemoveFile(config.TaskFile);err != nil { 111 | UI.Eval(notifyError(err.Error())) 112 | return 113 | } 114 | err := ioutil.WriteFile(config.TaskFile, []byte(t), os.ModeAppend) 115 | if err != nil { 116 | UI.Eval(notifyError(err.Error())) 117 | return 118 | } 119 | UI.Eval(notifySuccess("任务保存成功")) 120 | } 121 | 122 | func getJsonTask() string { 123 | if helper.FileIsExisted(config.TaskFile){ 124 | b, err := ioutil.ReadFile(config.TaskFile) 125 | if err != nil { 126 | UI.Eval(notifyError(err.Error())) 127 | return "[]" 128 | } 129 | return string(b) 130 | } 131 | return "[]" 132 | } 133 | 134 | -------------------------------------------------------------------------------- /tasks/screenshot.go: -------------------------------------------------------------------------------- 1 | package tasks 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "github.com/asaskevich/govalidator" 7 | "github.com/chromedp/cdproto/emulation" 8 | "github.com/chromedp/cdproto/page" 9 | "github.com/chromedp/chromedp" 10 | "github.com/mitchellh/mapstructure" 11 | "io/ioutil" 12 | "math" 13 | ) 14 | 15 | //截屏,全屏或者截取某个元素 16 | func (t *Task) screenshot(args taskArgs) error { 17 | var expectArgs struct { 18 | Sel string 19 | FullPage bool 20 | FileName string `valid:"required"` 21 | } 22 | if err := mapstructure.Decode(args, &expectArgs); err != nil { 23 | return errors.New("screenshot子任务出错:" + err.Error()) 24 | } 25 | 26 | if _, err := govalidator.ValidateStruct(&expectArgs); err != nil { 27 | return errors.New("screenshot子任务参数出错:" + err.Error()) 28 | } 29 | 30 | var err error 31 | var file []byte 32 | 33 | if expectArgs.FullPage { 34 | err = chromedp.Run(*t.ctx, fullPage(100, &file)) 35 | } else { 36 | err = chromedp.Run(*t.ctx, element(expectArgs.Sel, &file)) 37 | } 38 | if err != nil { 39 | return errors.New("screenshot子任务出错:" + err.Error()) 40 | } 41 | if err := ioutil.WriteFile(t.workDir()+"/"+expectArgs.FileName, file, 0666); err != nil { 42 | return err 43 | } 44 | return nil 45 | } 46 | 47 | //截取当前视窗 48 | func (t *Task) captureScreenshot(args taskArgs) error { 49 | var expectArgs struct { 50 | FileName string `valid:"required"` 51 | } 52 | if err := mapstructure.Decode(args, &expectArgs); err != nil { 53 | return errors.New("captureScreenshot子任务出错:" + err.Error()) 54 | } 55 | 56 | if _, err := govalidator.ValidateStruct(&expectArgs); err != nil { 57 | return errors.New("captureScreenshot子任务参数出错:" + err.Error()) 58 | } 59 | 60 | var file []byte 61 | err := chromedp.Run(*t.ctx, chromedp.CaptureScreenshot(&file)) 62 | 63 | if err != nil { 64 | return errors.New("captureScreenshot子任务出错:" + err.Error()) 65 | } 66 | if err := ioutil.WriteFile(t.workDir()+"/"+expectArgs.FileName, file, 0666); err != nil { 67 | return err 68 | } 69 | 70 | return nil 71 | } 72 | 73 | func element(sel string, res *[]byte) chromedp.Tasks { 74 | 75 | return chromedp.Tasks{ 76 | chromedp.WaitVisible(sel), 77 | chromedp.Screenshot(sel, res, chromedp.NodeVisible), 78 | } 79 | } 80 | 81 | func fullPage(quality int64, res *[]byte) chromedp.Tasks { 82 | return chromedp.Tasks{ 83 | chromedp.ActionFunc(func(ctx context.Context) error { 84 | _, _, contentSize, err := page.GetLayoutMetrics().Do(ctx) 85 | if err != nil { 86 | return err 87 | } 88 | 89 | width, height := int64(math.Ceil(contentSize.Width)), int64(math.Ceil(contentSize.Height)) 90 | 91 | // force viewport emulation 92 | err = emulation.SetDeviceMetricsOverride(width, height, 1, false). 93 | WithScreenOrientation(&emulation.ScreenOrientation{ 94 | Type: emulation.OrientationTypePortraitPrimary, 95 | Angle: 0, 96 | }). 97 | Do(ctx) 98 | if err != nil { 99 | return err 100 | } 101 | 102 | *res, err = page.CaptureScreenshot(). 103 | WithQuality(quality). 104 | WithClip(&page.Viewport{ 105 | X: contentSize.X, 106 | Y: contentSize.Y, 107 | Width: contentSize.Width, 108 | Height: contentSize.Height, 109 | Scale: 1, 110 | }).Do(ctx) 111 | if err != nil { 112 | return err 113 | } 114 | return nil 115 | }), 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /tasks/base.go: -------------------------------------------------------------------------------- 1 | package tasks 2 | 3 | import ( 4 | "errors" 5 | "github.com/asaskevich/govalidator" 6 | "github.com/chromedp/chromedp" 7 | "github.com/mitchellh/mapstructure" 8 | "time" 9 | ) 10 | 11 | //导航 12 | func (t *Task) navigate(args taskArgs) error { 13 | 14 | var expectArgs struct { 15 | Host string `valid:"requrl"` 16 | } 17 | 18 | if err := mapstructure.Decode(args, &expectArgs); err != nil { 19 | return errors.New("navigate子任务出错:" + err.Error()) 20 | } 21 | 22 | if _, err := govalidator.ValidateStruct(&expectArgs); err != nil { 23 | return errors.New("navigate子任务参数出错:" + err.Error()) 24 | } 25 | return chromedp.Run(*t.ctx, chromedp.Navigate(expectArgs.Host)) 26 | } 27 | 28 | //调整浏览器大小 29 | func (t *Task) emulateViewport(args taskArgs) error { 30 | 31 | var expectArgs struct { 32 | Width int64 `valid:"required"` 33 | Height int64 `valid:"required"` 34 | } 35 | 36 | if err := mapstructure.Decode(args, &expectArgs); err != nil { 37 | return errors.New("emulateViewport子任务出错:" + err.Error()) 38 | } 39 | 40 | if _, err := govalidator.ValidateStruct(&expectArgs); err != nil { 41 | return errors.New("emulateViewport子任务参数出错:" + err.Error()) 42 | } 43 | return chromedp.Run(*t.ctx, chromedp.EmulateViewport(expectArgs.Width, expectArgs.Height)) 44 | } 45 | 46 | //等待元素加载 47 | func (t *Task) waitVisible(args taskArgs) error { 48 | var expectArgs struct { 49 | Sel string `valid:"required"` 50 | } 51 | 52 | if err := mapstructure.Decode(args, &expectArgs); err != nil { 53 | return errors.New("waitVisible子任务出错:" + err.Error()) 54 | } 55 | 56 | if _, err := govalidator.ValidateStruct(&expectArgs); err != nil { 57 | return errors.New("waitVisible子任务参数出错:" + err.Error()) 58 | } 59 | return chromedp.Run(*t.ctx, chromedp.WaitVisible(expectArgs.Sel)) 60 | } 61 | 62 | //输入内容,覆盖之前的 63 | func (t *Task) setValue (args taskArgs) error { 64 | var expectArgs struct { 65 | Sel string `valid:"required"` 66 | Val string `valid:"required"` 67 | } 68 | 69 | if err := mapstructure.Decode(args, &expectArgs); err != nil { 70 | return errors.New("sendKeys子任务出错:" + err.Error()) 71 | } 72 | 73 | if _, err := govalidator.ValidateStruct(&expectArgs); err != nil { 74 | return errors.New("sendKeys子任务参数出错:" + err.Error()) 75 | } 76 | return chromedp.Run(*t.ctx, chromedp.SetValue(expectArgs.Sel, expectArgs.Val)) 77 | } 78 | 79 | //点击元素 80 | func (t *Task) click(args taskArgs) error { 81 | var expectArgs struct { 82 | Sel string `valid:"required"` 83 | } 84 | 85 | if err := mapstructure.Decode(args, &expectArgs); err != nil { 86 | return errors.New("click子任务出错:" + err.Error()) 87 | } 88 | 89 | if _, err := govalidator.ValidateStruct(&expectArgs); err != nil { 90 | return errors.New("click子任务参数出错:" + err.Error()) 91 | } 92 | return chromedp.Run(*t.ctx, chromedp.Click(expectArgs.Sel, chromedp.NodeVisible)) 93 | } 94 | //休眠 95 | func (t *Task) sleep(args taskArgs) error { 96 | var expectArgs struct { 97 | Second time.Duration `valid:"required"` 98 | } 99 | 100 | if err := mapstructure.Decode(args, &expectArgs); err != nil { 101 | return errors.New("sleep子任务出错:" + err.Error()) 102 | } 103 | 104 | if _, err := govalidator.ValidateStruct(&expectArgs); err != nil { 105 | return errors.New("sleep子任务参数出错:" + err.Error()) 106 | } 107 | return chromedp.Run(*t.ctx, chromedp.Sleep(expectArgs.Second * time.Second)) 108 | } 109 | -------------------------------------------------------------------------------- /public/src/components/taskPanel/TaskCard.vue: -------------------------------------------------------------------------------- 1 | 31 | 32 | 53 | 54 | 126 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef h1:46PFijGLmAjMPwCCCo7Jf0W6f9slllCkkv7vyc1yOSg= 2 | github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= 3 | github.com/chromedp/cdproto v0.0.0-20210222063305-a3ac505ff0bd h1:NpLicpTmd1m6SqIR0VjR24IaQXHJe/t11P2d2xKGx90= 4 | github.com/chromedp/cdproto v0.0.0-20210222063305-a3ac505ff0bd/go.mod h1:At5TxYYdxkbQL0TSefRjhLE3Q0lgvqKKMSFUglJ7i1U= 5 | github.com/chromedp/chromedp v0.6.6 h1:/cxTTWu097YeUBdFNuwe65crupzNP9CFVotrO1JzAdc= 6 | github.com/chromedp/chromedp v0.6.6/go.mod h1:I+DAskCTsBRt/48EVXbfmIUdMsSIyTR3sdxrCOXlrLY= 7 | github.com/chromedp/sysutil v1.0.0 h1:+ZxhTpfpZlmchB58ih/LBHX52ky7w2VhQVKQMucy3Ic= 8 | github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww= 9 | github.com/disintegration/imaging v1.6.0/go.mod h1:xuIt+sRxDFrHS0drzXUlCJthkJ8k7lkkUojDSR247MQ= 10 | github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU= 11 | github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= 12 | github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og= 13 | github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= 14 | github.com/gobwas/ws v1.0.4 h1:5eXU1CZhpQdq5kXbKb+sECH5Ia5KiO6CYzIzdlVx6Bs= 15 | github.com/gobwas/ws v1.0.4/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= 16 | github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= 17 | github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= 18 | github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= 19 | github.com/knq/sysutil v0.0.0-20181215143952-f05b59f0f307/go.mod h1:BjPj+aVjl9FW/cCGiF3nGh5v+9Gd3VCgBQbod/GlMaQ= 20 | github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= 21 | github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= 22 | github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= 23 | github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= 24 | github.com/zserge/lorca v0.1.9 h1:vbDdkqdp2/rmeg8GlyCewY2X8Z+b0s7BqWyIQL/gakc= 25 | github.com/zserge/lorca v0.1.9/go.mod h1:bVmnIbIRlOcoV285KIRSe4bUABKi7R7384Ycuum6e4A= 26 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= 27 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 28 | golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= 29 | golang.org/x/image v0.0.0-20190417020941-4e30a6eb7d9a/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= 30 | golang.org/x/net v0.0.0-20200222125558-5a598a2470a0 h1:MsuvTghUPjX762sGLnGsxC3HM0B5r83wEtYcYR8/vRs= 31 | golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 32 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU= 33 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 34 | golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43 h1:SgQ6LNaYJU0JIuEHv9+s6EbhSCwYeAf5Yvj6lpYlqAE= 35 | golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 36 | golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= 37 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 38 | -------------------------------------------------------------------------------- /public/src/components/taskPanel/EditTask.vue: -------------------------------------------------------------------------------- 1 | 51 | 52 | 118 | -------------------------------------------------------------------------------- /public/src/components/taskPanel/EditSubTask.vue: -------------------------------------------------------------------------------- 1 | 59 | 60 | 131 | 132 | 149 | -------------------------------------------------------------------------------- /public/src/components/taskPanel/Tasks.vue: -------------------------------------------------------------------------------- 1 | 78 | 79 | 144 | 145 | 230 | -------------------------------------------------------------------------------- /public/yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@babel/helper-validator-identifier@^7.12.11": 6 | version "7.12.11" 7 | resolved "https://registry.npm.taobao.org/@babel/helper-validator-identifier/download/@babel/helper-validator-identifier-7.12.11.tgz?cache=0&sync_timestamp=1608075248751&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-validator-identifier%2Fdownload%2F%40babel%2Fhelper-validator-identifier-7.12.11.tgz#c9a1f021917dcb5ccf0d4e453e399022981fc9ed" 8 | integrity sha1-yaHwIZF9y1zPDU5FPjmQIpgfye0= 9 | 10 | "@babel/parser@^7.12.0": 11 | version "7.13.0" 12 | resolved "https://registry.npm.taobao.org/@babel/parser/download/@babel/parser-7.13.0.tgz?cache=0&sync_timestamp=1614034252382&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fparser%2Fdownload%2F%40babel%2Fparser-7.13.0.tgz#49b9b6ee213e5634fa80361dae139effef893f78" 13 | integrity sha1-Sbm27iE+VjT6gDYdrhOe/++JP3g= 14 | 15 | "@babel/types@^7.12.0": 16 | version "7.13.0" 17 | resolved "https://registry.npm.taobao.org/@babel/types/download/@babel/types-7.13.0.tgz?cache=0&sync_timestamp=1614034253440&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Ftypes%2Fdownload%2F%40babel%2Ftypes-7.13.0.tgz#74424d2816f0171b4100f0ab34e9a374efdf7f80" 18 | integrity sha1-dEJNKBbwFxtBAPCrNOmjdO/ff4A= 19 | dependencies: 20 | "@babel/helper-validator-identifier" "^7.12.11" 21 | lodash "^4.17.19" 22 | to-fast-properties "^2.0.0" 23 | 24 | "@popperjs/core@^2.4.4": 25 | version "2.8.3" 26 | resolved "https://registry.npm.taobao.org/@popperjs/core/download/@popperjs/core-2.8.3.tgz?cache=0&sync_timestamp=1613995241043&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40popperjs%2Fcore%2Fdownload%2F%40popperjs%2Fcore-2.8.3.tgz#8b4eae3d9dd470c022cb9238128db8b1906e7fca" 27 | integrity sha1-i06uPZ3UcMAiy5I4Eo24sZBuf8o= 28 | 29 | "@vitejs/plugin-vue@^1.0.4": 30 | version "1.1.4" 31 | resolved "https://registry.npm.taobao.org/@vitejs/plugin-vue/download/@vitejs/plugin-vue-1.1.4.tgz#1dd388519b75439b7733601b55238ca691864796" 32 | integrity sha1-HdOIUZt1Q5t3M2AbVSOMppGGR5Y= 33 | 34 | "@vue/compiler-core@3.0.5": 35 | version "3.0.5" 36 | resolved "https://registry.npm.taobao.org/@vue/compiler-core/download/@vue/compiler-core-3.0.5.tgz#a6e54cabe9536e74c6513acd2649f311af1d43ac" 37 | integrity sha1-puVMq+lTbnTGUTrNJknzEa8dQ6w= 38 | dependencies: 39 | "@babel/parser" "^7.12.0" 40 | "@babel/types" "^7.12.0" 41 | "@vue/shared" "3.0.5" 42 | estree-walker "^2.0.1" 43 | source-map "^0.6.1" 44 | 45 | "@vue/compiler-dom@3.0.5": 46 | version "3.0.5" 47 | resolved "https://registry.npm.taobao.org/@vue/compiler-dom/download/@vue/compiler-dom-3.0.5.tgz#7885a13e6d18f64dde8ebceec052ed2c102696c2" 48 | integrity sha1-eIWhPm0Y9k3ejrzuwFLtLBAmlsI= 49 | dependencies: 50 | "@vue/compiler-core" "3.0.5" 51 | "@vue/shared" "3.0.5" 52 | 53 | "@vue/compiler-sfc@^3.0.5": 54 | version "3.0.5" 55 | resolved "https://registry.npm.taobao.org/@vue/compiler-sfc/download/@vue/compiler-sfc-3.0.5.tgz#3ae08e60244a72faf9598361874fb7bdb5b1d37c" 56 | integrity sha1-OuCOYCRKcvr5WYNhh0+3vbWx03w= 57 | dependencies: 58 | "@babel/parser" "^7.12.0" 59 | "@babel/types" "^7.12.0" 60 | "@vue/compiler-core" "3.0.5" 61 | "@vue/compiler-dom" "3.0.5" 62 | "@vue/compiler-ssr" "3.0.5" 63 | "@vue/shared" "3.0.5" 64 | consolidate "^0.16.0" 65 | estree-walker "^2.0.1" 66 | hash-sum "^2.0.0" 67 | lru-cache "^5.1.1" 68 | magic-string "^0.25.7" 69 | merge-source-map "^1.1.0" 70 | postcss "^7.0.32" 71 | postcss-modules "^3.2.2" 72 | postcss-selector-parser "^6.0.4" 73 | source-map "^0.6.1" 74 | 75 | "@vue/compiler-ssr@3.0.5": 76 | version "3.0.5" 77 | resolved "https://registry.npm.taobao.org/@vue/compiler-ssr/download/@vue/compiler-ssr-3.0.5.tgz#7661ad891a0be948726c7f7ad1e425253c587b83" 78 | integrity sha1-dmGtiRoL6UhybH960eQlJTxYe4M= 79 | dependencies: 80 | "@vue/compiler-dom" "3.0.5" 81 | "@vue/shared" "3.0.5" 82 | 83 | "@vue/reactivity@3.0.5": 84 | version "3.0.5" 85 | resolved "https://registry.npm.taobao.org/@vue/reactivity/download/@vue/reactivity-3.0.5.tgz#e3789e4d523d845f9ae0b4d770e2b45594742fd2" 86 | integrity sha1-43ieTVI9hF+a4LTXcOK0VZR0L9I= 87 | dependencies: 88 | "@vue/shared" "3.0.5" 89 | 90 | "@vue/runtime-core@3.0.5": 91 | version "3.0.5" 92 | resolved "https://registry.npm.taobao.org/@vue/runtime-core/download/@vue/runtime-core-3.0.5.tgz#da6331d5f300d5794e9e0ebdc8a8bd72a9e19962" 93 | integrity sha1-2mMx1fMA1XlOng69yKi9cqnhmWI= 94 | dependencies: 95 | "@vue/reactivity" "3.0.5" 96 | "@vue/shared" "3.0.5" 97 | 98 | "@vue/runtime-dom@3.0.5": 99 | version "3.0.5" 100 | resolved "https://registry.npm.taobao.org/@vue/runtime-dom/download/@vue/runtime-dom-3.0.5.tgz#1ce2c9c449e26ab06963da0064096e882a7a8935" 101 | integrity sha1-HOLJxEniarBpY9oAZAluiCp6iTU= 102 | dependencies: 103 | "@vue/runtime-core" "3.0.5" 104 | "@vue/shared" "3.0.5" 105 | csstype "^2.6.8" 106 | 107 | "@vue/shared@3.0.5": 108 | version "3.0.5" 109 | resolved "https://registry.npm.taobao.org/@vue/shared/download/@vue/shared-3.0.5.tgz#c131d88bd6713cc4d93b3bb1372edb1983225ff0" 110 | integrity sha1-wTHYi9ZxPMTZOzuxNy7bGYMiX/A= 111 | 112 | ansi-styles@^3.2.1: 113 | version "3.2.1" 114 | resolved "https://registry.npm.taobao.org/ansi-styles/download/ansi-styles-3.2.1.tgz?cache=0&sync_timestamp=1611326384145&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fansi-styles%2Fdownload%2Fansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" 115 | integrity sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0= 116 | dependencies: 117 | color-convert "^1.9.0" 118 | 119 | anymatch@~3.1.1: 120 | version "3.1.1" 121 | resolved "https://registry.npm.taobao.org/anymatch/download/anymatch-3.1.1.tgz#c55ecf02185e2469259399310c173ce31233b142" 122 | integrity sha1-xV7PAhheJGklk5kxDBc84xIzsUI= 123 | dependencies: 124 | normalize-path "^3.0.0" 125 | picomatch "^2.0.4" 126 | 127 | async-validator@^3.4.0: 128 | version "3.5.1" 129 | resolved "https://registry.npm.taobao.org/async-validator/download/async-validator-3.5.1.tgz?cache=0&sync_timestamp=1605751798748&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fasync-validator%2Fdownload%2Fasync-validator-3.5.1.tgz#cd62b9688b2465f48420e27adb47760ab1b5559f" 130 | integrity sha1-zWK5aIskZfSEIOJ620d2CrG1VZ8= 131 | 132 | big.js@^5.2.2: 133 | version "5.2.2" 134 | resolved "https://registry.npm.taobao.org/big.js/download/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" 135 | integrity sha1-ZfCvOC9Xi83HQr2cKB6cstd2gyg= 136 | 137 | binary-extensions@^2.0.0: 138 | version "2.2.0" 139 | resolved "https://registry.npm.taobao.org/binary-extensions/download/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" 140 | integrity sha1-dfUC7q+f/eQvyYgpZFvk6na9ni0= 141 | 142 | bluebird@^3.7.2: 143 | version "3.7.2" 144 | resolved "https://registry.npm.taobao.org/bluebird/download/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" 145 | integrity sha1-nyKcFb4nJFT/qXOs4NvueaGww28= 146 | 147 | braces@~3.0.2: 148 | version "3.0.2" 149 | resolved "https://registry.npm.taobao.org/braces/download/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" 150 | integrity sha1-NFThpGLujVmeI23zNs2epPiv4Qc= 151 | dependencies: 152 | fill-range "^7.0.1" 153 | 154 | chalk@^2.4.2: 155 | version "2.4.2" 156 | resolved "https://registry.npm.taobao.org/chalk/download/chalk-2.4.2.tgz?cache=0&sync_timestamp=1591687042638&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fchalk%2Fdownload%2Fchalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" 157 | integrity sha1-zUJUFnelQzPPVBpJEIwUMrRMlCQ= 158 | dependencies: 159 | ansi-styles "^3.2.1" 160 | escape-string-regexp "^1.0.5" 161 | supports-color "^5.3.0" 162 | 163 | "chokidar@>=2.0.0 <4.0.0": 164 | version "3.5.1" 165 | resolved "https://registry.npm.taobao.org/chokidar/download/chokidar-3.5.1.tgz#ee9ce7bbebd2b79f49f304799d5468e31e14e68a" 166 | integrity sha1-7pznu+vSt59J8wR5nVRo4x4U5oo= 167 | dependencies: 168 | anymatch "~3.1.1" 169 | braces "~3.0.2" 170 | glob-parent "~5.1.0" 171 | is-binary-path "~2.1.0" 172 | is-glob "~4.0.1" 173 | normalize-path "~3.0.0" 174 | readdirp "~3.5.0" 175 | optionalDependencies: 176 | fsevents "~2.3.1" 177 | 178 | color-convert@^1.9.0: 179 | version "1.9.3" 180 | resolved "https://registry.npm.taobao.org/color-convert/download/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" 181 | integrity sha1-u3GFBpDh8TZWfeYp0tVHHe2kweg= 182 | dependencies: 183 | color-name "1.1.3" 184 | 185 | color-name@1.1.3: 186 | version "1.1.3" 187 | resolved "https://registry.npm.taobao.org/color-name/download/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" 188 | integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= 189 | 190 | colorette@^1.2.1: 191 | version "1.2.1" 192 | resolved "https://registry.npm.taobao.org/colorette/download/colorette-1.2.1.tgz?cache=0&sync_timestamp=1593955783467&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcolorette%2Fdownload%2Fcolorette-1.2.1.tgz#4d0b921325c14faf92633086a536db6e89564b1b" 193 | integrity sha1-TQuSEyXBT6+SYzCGpTbbbolWSxs= 194 | 195 | consolidate@^0.16.0: 196 | version "0.16.0" 197 | resolved "https://registry.npm.taobao.org/consolidate/download/consolidate-0.16.0.tgz?cache=0&sync_timestamp=1599596654038&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fconsolidate%2Fdownload%2Fconsolidate-0.16.0.tgz#a11864768930f2f19431660a65906668f5fbdc16" 198 | integrity sha1-oRhkdokw8vGUMWYKZZBmaPX73BY= 199 | dependencies: 200 | bluebird "^3.7.2" 201 | 202 | cssesc@^3.0.0: 203 | version "3.0.0" 204 | resolved "https://registry.npm.taobao.org/cssesc/download/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" 205 | integrity sha1-N3QZGZA7hoVl4cCep0dEXNGJg+4= 206 | 207 | csstype@^2.6.8: 208 | version "2.6.15" 209 | resolved "https://registry.npm.taobao.org/csstype/download/csstype-2.6.15.tgz#655901663db1d652f10cb57ac6af5a05972aea1f" 210 | integrity sha1-ZVkBZj2x1lLxDLV6xq9aBZcq6h8= 211 | 212 | dayjs@1.x: 213 | version "1.10.4" 214 | resolved "https://registry.npm.taobao.org/dayjs/download/dayjs-1.10.4.tgz#8e544a9b8683f61783f570980a8a80eaf54ab1e2" 215 | integrity sha1-jlRKm4aD9heD9XCYCoqA6vVKseI= 216 | 217 | element-plus@latest: 218 | version "1.0.2-beta.32" 219 | resolved "https://registry.npm.taobao.org/element-plus/download/element-plus-1.0.2-beta.32.tgz#228975cfc2255993ef7ccd90238cea9a707f0742" 220 | integrity sha1-Iol1z8IlWZPvfM2QI4zqmnB/B0I= 221 | dependencies: 222 | "@popperjs/core" "^2.4.4" 223 | async-validator "^3.4.0" 224 | dayjs "1.x" 225 | lodash "^4.17.20" 226 | mitt "^2.1.0" 227 | normalize-wheel "^1.0.1" 228 | resize-observer-polyfill "^1.5.1" 229 | 230 | emojis-list@^3.0.0: 231 | version "3.0.0" 232 | resolved "https://registry.npm.taobao.org/emojis-list/download/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" 233 | integrity sha1-VXBmIEatKeLpFucariYKvf9Pang= 234 | 235 | esbuild@^0.8.47: 236 | version "0.8.50" 237 | resolved "https://registry.npm.taobao.org/esbuild/download/esbuild-0.8.50.tgz#ebf24fde0cdad1a369789dd6fd7a820b0a01e46c" 238 | integrity sha1-6/JP3gza0aNpeJ3W/XqCCwoB5Gw= 239 | 240 | escape-string-regexp@^1.0.5: 241 | version "1.0.5" 242 | resolved "https://registry.npm.taobao.org/escape-string-regexp/download/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" 243 | integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= 244 | 245 | estree-walker@^2.0.1: 246 | version "2.0.2" 247 | resolved "https://registry.npm.taobao.org/estree-walker/download/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac" 248 | integrity sha1-UvAQF4wqTBF6d1fP6UKtt9LaTKw= 249 | 250 | fill-range@^7.0.1: 251 | version "7.0.1" 252 | resolved "https://registry.npm.taobao.org/fill-range/download/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" 253 | integrity sha1-GRmmp8df44ssfHflGYU12prN2kA= 254 | dependencies: 255 | to-regex-range "^5.0.1" 256 | 257 | fsevents@~2.3.1: 258 | version "2.3.2" 259 | resolved "https://registry.npm.taobao.org/fsevents/download/fsevents-2.3.2.tgz?cache=0&sync_timestamp=1612536546156&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ffsevents%2Fdownload%2Ffsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" 260 | integrity sha1-ilJveLj99GI7cJ4Ll1xSwkwC/Ro= 261 | 262 | function-bind@^1.1.1: 263 | version "1.1.1" 264 | resolved "https://registry.npm.taobao.org/function-bind/download/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" 265 | integrity sha1-pWiZ0+o8m6uHS7l3O3xe3pL0iV0= 266 | 267 | generic-names@^2.0.1: 268 | version "2.0.1" 269 | resolved "https://registry.npm.taobao.org/generic-names/download/generic-names-2.0.1.tgz#f8a378ead2ccaa7a34f0317b05554832ae41b872" 270 | integrity sha1-+KN46tLMqno08DF7BVVIMq5BuHI= 271 | dependencies: 272 | loader-utils "^1.1.0" 273 | 274 | glob-parent@~5.1.0: 275 | version "5.1.1" 276 | resolved "https://registry.npm.taobao.org/glob-parent/download/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229" 277 | integrity sha1-tsHvQXxOVmPqSY8cRa+saRa7wik= 278 | dependencies: 279 | is-glob "^4.0.1" 280 | 281 | has-flag@^3.0.0: 282 | version "3.0.0" 283 | resolved "https://registry.npm.taobao.org/has-flag/download/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" 284 | integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= 285 | 286 | has@^1.0.3: 287 | version "1.0.3" 288 | resolved "https://registry.npm.taobao.org/has/download/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" 289 | integrity sha1-ci18v8H2qoJB8W3YFOAR4fQeh5Y= 290 | dependencies: 291 | function-bind "^1.1.1" 292 | 293 | hash-sum@^2.0.0: 294 | version "2.0.0" 295 | resolved "https://registry.npm.taobao.org/hash-sum/download/hash-sum-2.0.0.tgz#81d01bb5de8ea4a214ad5d6ead1b523460b0b45a" 296 | integrity sha1-gdAbtd6OpKIUrV1urRtSNGCwtFo= 297 | 298 | icss-replace-symbols@^1.1.0: 299 | version "1.1.0" 300 | resolved "https://registry.npm.taobao.org/icss-replace-symbols/download/icss-replace-symbols-1.1.0.tgz#06ea6f83679a7749e386cfe1fe812ae5db223ded" 301 | integrity sha1-Bupvg2ead0njhs/h/oEq5dsiPe0= 302 | 303 | icss-utils@^4.0.0, icss-utils@^4.1.1: 304 | version "4.1.1" 305 | resolved "https://registry.npm.taobao.org/icss-utils/download/icss-utils-4.1.1.tgz?cache=0&sync_timestamp=1605801644876&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ficss-utils%2Fdownload%2Ficss-utils-4.1.1.tgz#21170b53789ee27447c2f47dd683081403f9a467" 306 | integrity sha1-IRcLU3ie4nRHwvR91oMIFAP5pGc= 307 | dependencies: 308 | postcss "^7.0.14" 309 | 310 | indexes-of@^1.0.1: 311 | version "1.0.1" 312 | resolved "https://registry.npm.taobao.org/indexes-of/download/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607" 313 | integrity sha1-8w9xbI4r00bHtn0985FVZqfAVgc= 314 | 315 | is-binary-path@~2.1.0: 316 | version "2.1.0" 317 | resolved "https://registry.npm.taobao.org/is-binary-path/download/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" 318 | integrity sha1-6h9/O4DwZCNug0cPhsCcJU+0Wwk= 319 | dependencies: 320 | binary-extensions "^2.0.0" 321 | 322 | is-core-module@^2.2.0: 323 | version "2.2.0" 324 | resolved "https://registry.npm.taobao.org/is-core-module/download/is-core-module-2.2.0.tgz?cache=0&sync_timestamp=1606411557629&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fis-core-module%2Fdownload%2Fis-core-module-2.2.0.tgz#97037ef3d52224d85163f5597b2b63d9afed981a" 325 | integrity sha1-lwN+89UiJNhRY/VZeytj2a/tmBo= 326 | dependencies: 327 | has "^1.0.3" 328 | 329 | is-extglob@^2.1.1: 330 | version "2.1.1" 331 | resolved "https://registry.npm.taobao.org/is-extglob/download/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" 332 | integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= 333 | 334 | is-glob@^4.0.1, is-glob@~4.0.1: 335 | version "4.0.1" 336 | resolved "https://registry.npm.taobao.org/is-glob/download/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" 337 | integrity sha1-dWfb6fL14kZ7x3q4PEopSCQHpdw= 338 | dependencies: 339 | is-extglob "^2.1.1" 340 | 341 | is-number@^7.0.0: 342 | version "7.0.0" 343 | resolved "https://registry.npm.taobao.org/is-number/download/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" 344 | integrity sha1-dTU0W4lnNNX4DE0GxQlVUnoU8Ss= 345 | 346 | json5@^1.0.1: 347 | version "1.0.1" 348 | resolved "https://registry.npm.taobao.org/json5/download/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" 349 | integrity sha1-d5+wAYYE+oVOrL9iUhgNg1Q+Pb4= 350 | dependencies: 351 | minimist "^1.2.0" 352 | 353 | loader-utils@^1.1.0: 354 | version "1.4.0" 355 | resolved "https://registry.npm.taobao.org/loader-utils/download/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613" 356 | integrity sha1-xXm140yzSxp07cbB+za/o3HVphM= 357 | dependencies: 358 | big.js "^5.2.2" 359 | emojis-list "^3.0.0" 360 | json5 "^1.0.1" 361 | 362 | lodash.camelcase@^4.3.0: 363 | version "4.3.0" 364 | resolved "https://registry.npm.taobao.org/lodash.camelcase/download/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" 365 | integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY= 366 | 367 | lodash@^4.17.19, lodash@^4.17.20: 368 | version "4.17.21" 369 | resolved "https://registry.npm.taobao.org/lodash/download/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" 370 | integrity sha1-Z5WRxWTDv/quhFTPCz3zcMPWkRw= 371 | 372 | lru-cache@^5.1.1: 373 | version "5.1.1" 374 | resolved "https://registry.npm.taobao.org/lru-cache/download/lru-cache-5.1.1.tgz?cache=0&sync_timestamp=1594427569171&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flru-cache%2Fdownload%2Flru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" 375 | integrity sha1-HaJ+ZxAnGUdpXa9oSOhH8B2EuSA= 376 | dependencies: 377 | yallist "^3.0.2" 378 | 379 | magic-string@^0.25.7: 380 | version "0.25.7" 381 | resolved "https://registry.npm.taobao.org/magic-string/download/magic-string-0.25.7.tgz#3f497d6fd34c669c6798dcb821f2ef31f5445051" 382 | integrity sha1-P0l9b9NMZpxnmNy4IfLvMfVEUFE= 383 | dependencies: 384 | sourcemap-codec "^1.4.4" 385 | 386 | merge-source-map@^1.1.0: 387 | version "1.1.0" 388 | resolved "https://registry.npm.taobao.org/merge-source-map/download/merge-source-map-1.1.0.tgz#2fdde7e6020939f70906a68f2d7ae685e4c8c646" 389 | integrity sha1-L93n5gIJOfcJBqaPLXrmheTIxkY= 390 | dependencies: 391 | source-map "^0.6.1" 392 | 393 | minimist@^1.2.0: 394 | version "1.2.5" 395 | resolved "https://registry.npm.taobao.org/minimist/download/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" 396 | integrity sha1-Z9ZgFLZqaoqqDAg8X9WN9OTpdgI= 397 | 398 | mitt@^2.1.0: 399 | version "2.1.0" 400 | resolved "https://registry.npm.taobao.org/mitt/download/mitt-2.1.0.tgz?cache=0&sync_timestamp=1594823602623&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmitt%2Fdownload%2Fmitt-2.1.0.tgz#f740577c23176c6205b121b2973514eade1b2230" 401 | integrity sha1-90BXfCMXbGIFsSGylzUU6t4bIjA= 402 | 403 | nanoid@^3.1.20: 404 | version "3.1.20" 405 | resolved "https://registry.npm.taobao.org/nanoid/download/nanoid-3.1.20.tgz#badc263c6b1dcf14b71efaa85f6ab4c1d6cfc788" 406 | integrity sha1-utwmPGsdzxS3HvqoX2q0wdbPx4g= 407 | 408 | normalize-path@^3.0.0, normalize-path@~3.0.0: 409 | version "3.0.0" 410 | resolved "https://registry.npm.taobao.org/normalize-path/download/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" 411 | integrity sha1-Dc1p/yOhybEf0JeDFmRKA4ghamU= 412 | 413 | normalize-wheel@^1.0.1: 414 | version "1.0.1" 415 | resolved "https://registry.npm.taobao.org/normalize-wheel/download/normalize-wheel-1.0.1.tgz#aec886affdb045070d856447df62ecf86146ec45" 416 | integrity sha1-rsiGr/2wRQcNhWRH32Ls+GFG7EU= 417 | 418 | path-parse@^1.0.6: 419 | version "1.0.6" 420 | resolved "https://registry.npm.taobao.org/path-parse/download/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" 421 | integrity sha1-1i27VnlAXXLEc37FhgDp3c8G0kw= 422 | 423 | picomatch@^2.0.4, picomatch@^2.2.1: 424 | version "2.2.2" 425 | resolved "https://registry.npm.taobao.org/picomatch/download/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad" 426 | integrity sha1-IfMz6ba46v8CRo9RRupAbTRfTa0= 427 | 428 | postcss-modules-extract-imports@^2.0.0: 429 | version "2.0.0" 430 | resolved "https://registry.npm.taobao.org/postcss-modules-extract-imports/download/postcss-modules-extract-imports-2.0.0.tgz?cache=0&sync_timestamp=1602588417522&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpostcss-modules-extract-imports%2Fdownload%2Fpostcss-modules-extract-imports-2.0.0.tgz#818719a1ae1da325f9832446b01136eeb493cd7e" 431 | integrity sha1-gYcZoa4doyX5gyRGsBE27rSTzX4= 432 | dependencies: 433 | postcss "^7.0.5" 434 | 435 | postcss-modules-local-by-default@^3.0.2: 436 | version "3.0.3" 437 | resolved "https://registry.npm.taobao.org/postcss-modules-local-by-default/download/postcss-modules-local-by-default-3.0.3.tgz#bb14e0cc78279d504dbdcbfd7e0ca28993ffbbb0" 438 | integrity sha1-uxTgzHgnnVBNvcv9fgyiiZP/u7A= 439 | dependencies: 440 | icss-utils "^4.1.1" 441 | postcss "^7.0.32" 442 | postcss-selector-parser "^6.0.2" 443 | postcss-value-parser "^4.1.0" 444 | 445 | postcss-modules-scope@^2.2.0: 446 | version "2.2.0" 447 | resolved "https://registry.npm.taobao.org/postcss-modules-scope/download/postcss-modules-scope-2.2.0.tgz?cache=0&sync_timestamp=1602593137586&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpostcss-modules-scope%2Fdownload%2Fpostcss-modules-scope-2.2.0.tgz#385cae013cc7743f5a7d7602d1073a89eaae62ee" 448 | integrity sha1-OFyuATzHdD9afXYC0Qc6iequYu4= 449 | dependencies: 450 | postcss "^7.0.6" 451 | postcss-selector-parser "^6.0.0" 452 | 453 | postcss-modules-values@^3.0.0: 454 | version "3.0.0" 455 | resolved "https://registry.npm.taobao.org/postcss-modules-values/download/postcss-modules-values-3.0.0.tgz#5b5000d6ebae29b4255301b4a3a54574423e7f10" 456 | integrity sha1-W1AA1uuuKbQlUwG0o6VFdEI+fxA= 457 | dependencies: 458 | icss-utils "^4.0.0" 459 | postcss "^7.0.6" 460 | 461 | postcss-modules@^3.2.2: 462 | version "3.2.2" 463 | resolved "https://registry.npm.taobao.org/postcss-modules/download/postcss-modules-3.2.2.tgz?cache=0&sync_timestamp=1606644453415&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpostcss-modules%2Fdownload%2Fpostcss-modules-3.2.2.tgz#ee390de0f9f18e761e1778dfb9be26685c02c51f" 464 | integrity sha1-7jkN4PnxjnYeF3jfub4maFwCxR8= 465 | dependencies: 466 | generic-names "^2.0.1" 467 | icss-replace-symbols "^1.1.0" 468 | lodash.camelcase "^4.3.0" 469 | postcss "^7.0.32" 470 | postcss-modules-extract-imports "^2.0.0" 471 | postcss-modules-local-by-default "^3.0.2" 472 | postcss-modules-scope "^2.2.0" 473 | postcss-modules-values "^3.0.0" 474 | string-hash "^1.1.1" 475 | 476 | postcss-selector-parser@^6.0.0, postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4: 477 | version "6.0.4" 478 | resolved "https://registry.npm.taobao.org/postcss-selector-parser/download/postcss-selector-parser-6.0.4.tgz?cache=0&sync_timestamp=1601045323543&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpostcss-selector-parser%2Fdownload%2Fpostcss-selector-parser-6.0.4.tgz#56075a1380a04604c38b063ea7767a129af5c2b3" 479 | integrity sha1-VgdaE4CgRgTDiwY+p3Z6Epr1wrM= 480 | dependencies: 481 | cssesc "^3.0.0" 482 | indexes-of "^1.0.1" 483 | uniq "^1.0.1" 484 | util-deprecate "^1.0.2" 485 | 486 | postcss-value-parser@^4.1.0: 487 | version "4.1.0" 488 | resolved "https://registry.npm.taobao.org/postcss-value-parser/download/postcss-value-parser-4.1.0.tgz#443f6a20ced6481a2bda4fa8532a6e55d789a2cb" 489 | integrity sha1-RD9qIM7WSBor2k+oUypuVdeJoss= 490 | 491 | postcss@^7.0.14, postcss@^7.0.32, postcss@^7.0.5, postcss@^7.0.6: 492 | version "7.0.35" 493 | resolved "https://registry.npm.taobao.org/postcss/download/postcss-7.0.35.tgz#d2be00b998f7f211d8a276974079f2e92b970e24" 494 | integrity sha1-0r4AuZj38hHYonaXQHny6SuXDiQ= 495 | dependencies: 496 | chalk "^2.4.2" 497 | source-map "^0.6.1" 498 | supports-color "^6.1.0" 499 | 500 | postcss@^8.2.1: 501 | version "8.2.6" 502 | resolved "https://registry.npm.taobao.org/postcss/download/postcss-8.2.6.tgz#5d69a974543b45f87e464bc4c3e392a97d6be9fe" 503 | integrity sha1-XWmpdFQ7Rfh+RkvEw+OSqX1r6f4= 504 | dependencies: 505 | colorette "^1.2.1" 506 | nanoid "^3.1.20" 507 | source-map "^0.6.1" 508 | 509 | readdirp@~3.5.0: 510 | version "3.5.0" 511 | resolved "https://registry.npm.taobao.org/readdirp/download/readdirp-3.5.0.tgz#9ba74c019b15d365278d2e91bb8c48d7b4d42c9e" 512 | integrity sha1-m6dMAZsV02UnjS6Ru4xI17TULJ4= 513 | dependencies: 514 | picomatch "^2.2.1" 515 | 516 | resize-observer-polyfill@^1.5.1: 517 | version "1.5.1" 518 | resolved "https://registry.npm.taobao.org/resize-observer-polyfill/download/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464" 519 | integrity sha1-DpAg3T0hAkRY1OvSfiPkAmmBBGQ= 520 | 521 | resolve@^1.19.0: 522 | version "1.20.0" 523 | resolved "https://registry.npm.taobao.org/resolve/download/resolve-1.20.0.tgz?cache=0&sync_timestamp=1613054898763&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fresolve%2Fdownload%2Fresolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" 524 | integrity sha1-YpoBP7P3B1XW8LeTXMHCxTeLGXU= 525 | dependencies: 526 | is-core-module "^2.2.0" 527 | path-parse "^1.0.6" 528 | 529 | rollup@^2.38.5: 530 | version "2.39.1" 531 | resolved "https://registry.npm.taobao.org/rollup/download/rollup-2.39.1.tgz#7afd4cefd8a332c5102a8063d301fde1f31a9173" 532 | integrity sha1-ev1M79ijMsUQKoBj0wH94fMakXM= 533 | optionalDependencies: 534 | fsevents "~2.3.1" 535 | 536 | sass@^1.32.8: 537 | version "1.32.8" 538 | resolved "https://registry.npm.taobao.org/sass/download/sass-1.32.8.tgz#f16a9abd8dc530add8834e506878a2808c037bdc" 539 | integrity sha1-8WqavY3FMK3Yg05QaHiigIwDe9w= 540 | dependencies: 541 | chokidar ">=2.0.0 <4.0.0" 542 | 543 | source-map@^0.6.1: 544 | version "0.6.1" 545 | resolved "https://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz?cache=0&sync_timestamp=1604409581245&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsource-map%2Fdownload%2Fsource-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" 546 | integrity sha1-dHIq8y6WFOnCh6jQu95IteLxomM= 547 | 548 | sourcemap-codec@^1.4.4: 549 | version "1.4.8" 550 | resolved "https://registry.npm.taobao.org/sourcemap-codec/download/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" 551 | integrity sha1-6oBL2UhXQC5pktBaOO8a41qatMQ= 552 | 553 | string-hash@^1.1.1: 554 | version "1.1.3" 555 | resolved "https://registry.npm.taobao.org/string-hash/download/string-hash-1.1.3.tgz#e8aafc0ac1855b4666929ed7dd1275df5d6c811b" 556 | integrity sha1-6Kr8CsGFW0Zmkp7X3RJ1311sgRs= 557 | 558 | supports-color@^5.3.0: 559 | version "5.5.0" 560 | resolved "https://registry.npm.taobao.org/supports-color/download/supports-color-5.5.0.tgz?cache=0&sync_timestamp=1611394404603&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsupports-color%2Fdownload%2Fsupports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" 561 | integrity sha1-4uaaRKyHcveKHsCzW2id9lMO/I8= 562 | dependencies: 563 | has-flag "^3.0.0" 564 | 565 | supports-color@^6.1.0: 566 | version "6.1.0" 567 | resolved "https://registry.npm.taobao.org/supports-color/download/supports-color-6.1.0.tgz?cache=0&sync_timestamp=1611394404603&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsupports-color%2Fdownload%2Fsupports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3" 568 | integrity sha1-B2Srxpxj1ayELdSGfo0CXogN+PM= 569 | dependencies: 570 | has-flag "^3.0.0" 571 | 572 | to-fast-properties@^2.0.0: 573 | version "2.0.0" 574 | resolved "https://registry.npm.taobao.org/to-fast-properties/download/to-fast-properties-2.0.0.tgz?cache=0&sync_timestamp=1580550296062&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fto-fast-properties%2Fdownload%2Fto-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" 575 | integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= 576 | 577 | to-regex-range@^5.0.1: 578 | version "5.0.1" 579 | resolved "https://registry.npm.taobao.org/to-regex-range/download/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" 580 | integrity sha1-FkjESq58jZiKMmAY7XL1tN0DkuQ= 581 | dependencies: 582 | is-number "^7.0.0" 583 | 584 | uniq@^1.0.1: 585 | version "1.0.1" 586 | resolved "https://registry.npm.taobao.org/uniq/download/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" 587 | integrity sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8= 588 | 589 | util-deprecate@^1.0.2: 590 | version "1.0.2" 591 | resolved "https://registry.npm.taobao.org/util-deprecate/download/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" 592 | integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= 593 | 594 | vite@^2.0.0-beta.12: 595 | version "2.0.2" 596 | resolved "https://registry.npm.taobao.org/vite/download/vite-2.0.2.tgz#d984528b5a1c8e725d2804245751769b11d671cf" 597 | integrity sha1-2YRSi1ocjnJdKAQkV1F2mxHWcc8= 598 | dependencies: 599 | esbuild "^0.8.47" 600 | postcss "^8.2.1" 601 | resolve "^1.19.0" 602 | rollup "^2.38.5" 603 | optionalDependencies: 604 | fsevents "~2.3.1" 605 | 606 | vue@^3.0.5: 607 | version "3.0.5" 608 | resolved "https://registry.npm.taobao.org/vue/download/vue-3.0.5.tgz?cache=0&sync_timestamp=1609359858533&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fvue%2Fdownload%2Fvue-3.0.5.tgz#de1b82eba24abfe71e0970fc9b8d4b2babdc3fe1" 609 | integrity sha1-3huC66JKv+ceCXD8m41LK6vcP+E= 610 | dependencies: 611 | "@vue/compiler-dom" "3.0.5" 612 | "@vue/runtime-dom" "3.0.5" 613 | "@vue/shared" "3.0.5" 614 | 615 | vuex@^4.0.0: 616 | version "4.0.0" 617 | resolved "https://registry.npm.taobao.org/vuex/download/vuex-4.0.0.tgz?cache=0&sync_timestamp=1612277435391&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fvuex%2Fdownload%2Fvuex-4.0.0.tgz#ac877aa76a9c45368c979471e461b520d38e6cf5" 618 | integrity sha1-rId6p2qcRTaMl5Rx5GG1INOObPU= 619 | 620 | yallist@^3.0.2: 621 | version "3.1.1" 622 | resolved "https://registry.npm.taobao.org/yallist/download/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" 623 | integrity sha1-27fa+b/YusmrRev2ArjLrQ1dCP0= 624 | --------------------------------------------------------------------------------