Jelajahi Sumber

Merge branch 'dev'

tangning 3 hari lalu
induk
melakukan
3665e522ca

+ 4 - 1
package.json

@@ -64,7 +64,10 @@
     "vue-i18n": "^9.1.9",
     "vue-router": "^4.0.12",
     "vue-types": "^4.1.1",
-    "xlsx": "^0.18.5"
+    "xlsx": "^0.18.5",
+    "xlsx-js-style": "^1.2.0",
+    "node-fetch": "^3.3.2",
+    "unzipper": "^0.12.3"
   },
   "devDependencies": {
     "@commitlint/cli": "^14.1.0",

+ 15 - 4
src/api/device/index.ts

@@ -1,5 +1,5 @@
 import { defHttp } from '/@/utils/http/axios';
-import { PageParams} from './model';
+import { PageParams } from './model';
 import { Result } from '/#/axios';
 
 enum Api {
@@ -8,8 +8,19 @@ enum Api {
   getOut = '/service/manage/camera/out',
   getDelete = '/service/manage/camera/delete',
   getIn = '/service/manage/camera/in',
+  giveCamLog = '/service/agent/camera/giveCamLog',
 }
 
+export const getGiveCamLog = (params: PageParams) =>
+  defHttp.get<Result>({
+    url: Api.giveCamLog,
+    params: params,
+    // data: params,
+    headers: {
+      // @ts-ignore
+      ignoreCancelToken: true,
+    },
+  });
 export const cameraParam = (params: PageParams) =>
   defHttp.get<Result>({
     url: Api.getParam,
@@ -32,7 +43,7 @@ export const cameraDelete = (params: PageParams) =>
     },
   });
 
-  export const cameraUpdate = (params: PageParams) =>
+export const cameraUpdate = (params: PageParams) =>
   defHttp.post<Result>({
     url: Api.getUpdate,
     params: params,
@@ -43,7 +54,7 @@ export const cameraDelete = (params: PageParams) =>
     },
   });
 
-  export const cameraOut = (params: PageParams) =>
+export const cameraOut = (params: PageParams) =>
   defHttp.post<Result>({
     url: Api.getOut,
     params: params,
@@ -63,4 +74,4 @@ export const cameraIn = (params: PageParams) =>
       // @ts-ignore
       ignoreCancelToken: true,
     },
-});
+  });

+ 886 - 44
src/locales/lang/json/en.json

@@ -1,48 +1,890 @@
 {
-  "code": {
-    "apiCode": {
-      "-1": "The operation failed",
-      "0": "Operation success",
-      "3014": "Account or password error, please login again!",
-      "4001": "Required field cannot be blank",
-      "4003": "User does not exist",
-      "4004": "User has been added",
-      "4005": "Reseller does not exist",
-      "4008": "User not logged in",
-      "4009": "Account or password error, please login again!",
-      "4011": "The scene does not currently exist",
-      "4012": "The camera does not currently exist",
-      "4013": "Cannot copy due to insufficient capacity",
-      "4014": "The scene must migrate under the same camera type!",
-      "4015": "The membership subscription category does not exist!",
-      "4016": "The membership subscription does not exist!",
-      "4017": "Insufficient number of membership subscriptions!",
-      "4018": "Insufficient number of downloads!",
-      "4019": "SN code does not exist!",
-      "4020": "Multiple login attempts detected, please try again in five minutes!",
-      "4021": "Distributor name already exists",
-      "4022": "The distributor account already exists",
-      "4028": "Template format error",
-      "4029": "There is an error in line {value}",
-      "4030": "Account deactivated, please contact administrator",
-      "4032": "Insufficient permissions",
-      "4033": "Add failed, duplicate authorization code exists",
-      "500": "Sorry, the server is reporting an error.",
-      "50009": "Please upgrade the V3 scene before recalculating.",
-      "50018": "Camera does not exist!",
-      "50031": "Insufficient camera capacity for migration",
-      "50032": "The scene must migrate under the same camera type!",
-      "50034": "SN code does not exist!",
-      "50044": "The scene is captured by this camera and no transfer is required!",
-      "50045": "The original resource has been removed, and the recalculation has failed.",
-      "5005": "Empty scene",
-      "50054": "Scene calculation in process, cannot be copied!",
-      "50055": "Replicated scenes do not enable transfer.",
-      "50056": "Duplicated scenes do not support recalculation.",
-      "50066": "The original resource has been frozen, recalculation failed!",
-      "50071": "Duplicated scenes do not support recalculation.",
-      "5037": "Calculating,please wait.",
-      "5071": "Duplicated scenes do not support recalculation."
+    "code": {
+        "apiCode": {
+            "0": "Operation success",
+            "500": "Sorry, the server is reporting an error.",
+            "3014": "Account or password error, please login again!",
+            "4001": "Required field cannot be blank",
+            "4003": "User does not exist",
+            "4004": "User has been added",
+            "4005": "Reseller does not exist",
+            "4008": "User not logged in",
+            "4009": "Account or password error, please login again!",
+            "4011": "The scene does not currently exist",
+            "4012": "The camera does not currently exist",
+            "4013": "Cannot copy due to insufficient capacity",
+            "4014": "The scene must migrate under the same camera type!",
+            "4015": "The membership subscription category does not exist!",
+            "4016": "The membership subscription does not exist!",
+            "4017": "Insufficient number of membership subscriptions!",
+            "4018": "Insufficient number of downloads!",
+            "4019": "SN code does not exist!",
+            "4020": "Multiple login attempts detected, please try again in five minutes!",
+            "4021": "Distributor name already exists",
+            "4022": "The distributor account already exists",
+            "4028": "Template format error",
+            "4029": "There is an error in line {value}",
+            "4030": "Account deactivated, please contact administrator",
+            "4032": "Insufficient permissions",
+            "4033": "Add failed, duplicate authorization code exists",
+            "5005": "Empty scene",
+            "5037": "Calculating,please wait.",
+            "5071": "Duplicated scenes do not support recalculation.",
+            "50009": "Please upgrade the V3 scene before recalculating.",
+            "50018": "Camera does not exist!",
+            "50031": "Insufficient camera capacity for migration",
+            "50032": "The scene must migrate under the same camera type!",
+            "50034": "SN code does not exist!",
+            "50044": "The scene is captured by this camera and no transfer is required!",
+            "50045": "The original resource has been removed, and the recalculation has failed.",
+            "50054": "Scene calculation in process, cannot be copied!",
+            "50055": "Replicated scenes do not enable transfer.",
+            "50056": "Duplicated scenes do not support recalculation.",
+            "50066": "The original resource has been frozen, recalculation failed!",
+            "50071": "Duplicated scenes do not support recalculation.",
+            "-1": "The operation failed"
+        }
+    },
+    "common": {
+        "okText": "OK",
+        "closeText": "Close",
+        "cancelText": "Cancel",
+        "loadingText": "Loading...",
+        "saveText": "Save",
+        "delText": "Delete",
+        "resetText": "Reset",
+        "searchText": "Search",
+        "queryText": "Search",
+        "state": "state",
+        "inputText": "Please enter ",
+        "chooseText": "Please choose ",
+        "edit": "Edit",
+        "redo": "Refresh",
+        "back": "Back",
+        "yes": "yes",
+        "no": "no",
+        "light": "Light",
+        "dark": "Dark",
+        "reminder": "reminder",
+        "operating": "Operation",
+        "uploadMessge": "Please select the upload file",
+        "optSuccess": "The operation was successful.",
+        "unit": {
+            "1": "",
+            "2": "",
+            "3": ""
+        }
+    },
+    "component": {
+        "app": {
+            "searchNotData": "No search results yet",
+            "toSearch": "to search",
+            "toNavigate": "to navigate"
+        },
+        "countdown": {
+            "normalText": "Get SMS code",
+            "sendText": "Reacquire in {0}s"
+        },
+        "cropper": {
+            "selectImage": "Select Image",
+            "uploadSuccess": "Uploaded success!",
+            "modalTitle": "Avatar upload",
+            "okText": "Confirm and upload",
+            "btn_reset": "Reset",
+            "btn_rotate_left": "Counterclockwise rotation",
+            "btn_rotate_right": "Clockwise rotation",
+            "btn_scale_x": "Flip horizontal",
+            "btn_scale_y": "Flip vertical",
+            "btn_zoom_in": "Zoom in",
+            "btn_zoom_out": "Zoom out",
+            "preview": "Preivew"
+        },
+        "drawer": {
+            "loadingText": "Loading...",
+            "cancelText": "Close",
+            "okText": "Confirm"
+        },
+        "excel": {
+            "exportModalTitle": "Export data",
+            "fileType": "File type",
+            "fileName": "File name"
+        },
+        "form": {
+            "putAway": "Put away",
+            "unfold": "Unfold",
+            "maxTip": "The number of characters should be less than {0}",
+            "apiSelectNotFound": "Wait for data loading to complete..."
+        },
+        "icon": {
+            "placeholder": "Click the select icon",
+            "search": "Search icon",
+            "copy": "Copy icon successfully!"
+        },
+        "menu": {
+            "search": "Menu search"
+        },
+        "modal": {
+            "cancelText": "Close",
+            "okText": "Confirm",
+            "close": "Close",
+            "maximize": "Maximize",
+            "restore": "Restore"
+        },
+        "table": {
+            "settingDens": "Density",
+            "settingDensDefault": "Default",
+            "settingDensMiddle": "Middle",
+            "settingDensSmall": "Compact",
+            "settingColumn": "Column settings",
+            "settingColumnShow": "Column display",
+            "settingIndexColumnShow": "Index Column",
+            "settingSelectColumnShow": "Selection Column",
+            "settingFixedLeft": "Fixed Left",
+            "settingFixedRight": "Fixed Right",
+            "settingFullScreen": "Full Screen",
+            "index": "Index",
+            "total": "total of {total}"
+        },
+        "time": {
+            "before": " ago",
+            "after": " after",
+            "just": "just now",
+            "seconds": " seconds",
+            "minutes": " minutes",
+            "hours": " hours",
+            "days": " days"
+        },
+        "tree": {
+            "selectAll": "Select All",
+            "unSelectAll": "Cancel Select",
+            "expandAll": "Expand All",
+            "unExpandAll": "Collapse all",
+            "checkStrictly": "Hierarchical association",
+            "checkUnStrictly": "Hierarchical independence"
+        },
+        "upload": {
+            "save": "Save",
+            "upload": "Upload",
+            "imgUpload": "ImageUpload",
+            "uploaded": "Uploaded",
+            "operating": "Operating",
+            "del": "Delete",
+            "download": "download",
+            "saveWarn": "Please wait for the file to upload and save!",
+            "saveError": "There is no file successfully uploaded and cannot be saved!",
+            "preview": "Preview",
+            "choose": "Select the file",
+            "accept": "Support {0} format",
+            "acceptUpload": "Only upload files in {0} format",
+            "maxSize": "A single file does not exceed {0}MB ",
+            "maxSizeMultiple": "Only upload files up to {0}MB!",
+            "maxNumber": "Only upload up to {0} files",
+            "legend": "Legend",
+            "fileName": "File name",
+            "fileSize": "File size",
+            "fileStatue": "File status",
+            "startUpload": "Start upload",
+            "uploadSuccess": "Upload successfully",
+            "uploadError": "Upload failed",
+            "uploading": "Uploading",
+            "uploadWait": "Please wait for the file upload to finish",
+            "reUploadFailed": "Re-upload failed files"
+        },
+        "verify": {
+            "error": "verification failed!",
+            "time": "The verification is successful and it takes {time} seconds!",
+            "redoTip": "Click the picture to refresh",
+            "dragText": "Hold down the slider and drag",
+            "successText": "Verified"
+        }
+    },
+    "layout": {
+        "footer": {
+            "onlinePreview": "Preview",
+            "onlineDocument": "Document"
+        },
+        "header": {
+            "dropdownItemDoc": "Document",
+            "dropdownItemLoginOut": "Login Out",
+            "tooltipErrorLog": "Error log",
+            "tooltipLock": "Lock screen",
+            "tooltipNotify": "Notification",
+            "tooltipEntryFull": "Full Screen",
+            "tooltipExitFull": "Exit Full Screen",
+            "lockScreenPassword": "Lock screen password",
+            "lockScreen": "Lock screen",
+            "lockScreenBtn": "Locking",
+            "home": "Home"
+        },
+        "multipleTab": {
+            "reload": "Refresh current",
+            "close": "Close current",
+            "closeLeft": "Close Left",
+            "closeRight": "Close Right",
+            "closeOther": "Close Other",
+            "closeAll": "Close All"
+        },
+        "setting": {
+            "contentModeFull": "Full",
+            "contentModeFixed": "Fixed width",
+            "topMenuAlignLeft": "Left",
+            "topMenuAlignRight": "Center",
+            "topMenuAlignCenter": "Right",
+            "menuTriggerNone": "Not Show",
+            "menuTriggerBottom": "Bottom",
+            "menuTriggerTop": "Top",
+            "menuTypeSidebar": "Left menu mode",
+            "menuTypeMixSidebar": "Left menu mixed mode",
+            "menuTypeMix": "Top Menu Mix mode",
+            "menuTypeTopMenu": "Top menu mode",
+            "on": "On",
+            "off": "Off",
+            "minute": "Minute",
+            "operatingTitle": "Successful!",
+            "operatingContent": "The copy is successful, please go to src/settings/projectSetting.ts to modify the configuration!",
+            "resetSuccess": "Successfully reset!",
+            "copyBtn": "Copy",
+            "clearBtn": "Clear cache and to the login page",
+            "drawerTitle": "Configuration",
+            "darkMode": "Dark mode",
+            "navMode": "Navigation mode",
+            "interfaceFunction": "Interface function",
+            "interfaceDisplay": "Interface display",
+            "animation": "Animation",
+            "splitMenu": "Split menu",
+            "closeMixSidebarOnChange": "Switch page to close menu",
+            "sysTheme": "System theme",
+            "headerTheme": "Header theme",
+            "sidebarTheme": "Menu theme",
+            "menuDrag": "Drag Sidebar",
+            "menuSearch": "Menu search",
+            "menuAccordion": "Sidebar accordion",
+            "menuCollapse": "Collapse menu",
+            "collapseMenuDisplayName": "Collapse menu display name",
+            "topMenuLayout": "Top menu layout",
+            "menuCollapseButton": "Menu collapse button",
+            "contentMode": "Content area width",
+            "expandedMenuWidth": "Expanded menu width",
+            "breadcrumb": "Breadcrumbs",
+            "breadcrumbIcon": "Breadcrumbs Icon",
+            "tabs": "Tabs",
+            "tabDetail": "Tab Detail",
+            "tabsQuickBtn": "Tabs quick button",
+            "tabsRedoBtn": "Tabs redo button",
+            "tabsFoldBtn": "Tabs flod button",
+            "sidebar": "Sidebar",
+            "header": "Header",
+            "footer": "Footer",
+            "fullContent": "Full content",
+            "grayMode": "Gray mode",
+            "colorWeak": "Color Weak Mode",
+            "progress": "Progress",
+            "switchLoading": "Switch Loading",
+            "switchAnimation": "Switch animation",
+            "animationType": "Animation type",
+            "autoScreenLock": "Auto screen lock",
+            "notAutoScreenLock": "Not auto lock",
+            "fixedHeader": "Fixed header",
+            "fixedSideBar": "Fixed Sidebar",
+            "mixSidebarTrigger": "Mixed menu Trigger",
+            "triggerHover": "Hover",
+            "triggerClick": "Click",
+            "mixSidebarFixed": "Fixed expanded menu"
+        }
+    },
+    "sys": {
+        "api": {
+            "operationFailed": "Operation failed",
+            "errorTip": "Error Tip",
+            "errorMessage": "The operation failed, the system is abnormal!",
+            "timeoutMessage": "Login timed out, please log in again!",
+            "apiTimeoutMessage": "The interface request timed out, please refresh the page and try again!",
+            "apiRequestFailed": "The interface request failed, please try again later!",
+            "networkException": "network anomaly",
+            "networkExceptionMsg": "Please check if your network connection is normal! The network is abnormal",
+            "errMsg401": "The user does not have permission (token, user name, password error)!",
+            "errMsg403": "The user is authorized, but access is forbidden!",
+            "errMsg404": "Network request error, the resource was not found!",
+            "errMsg405": "Network request error, request method not allowed!",
+            "errMsg408": "Network request timed out!",
+            "errMsg500": "Server error, please contact the administrator!",
+            "errMsg501": "The network is not implemented!",
+            "errMsg502": "Network Error!",
+            "errMsg503": "The service is unavailable, the server is temporarily overloaded or maintained!",
+            "errMsg504": "Network timeout!",
+            "errMsg505": "The http version does not support the request!"
+        },
+        "app": {
+            "logoutTip": "Reminder",
+            "logoutMessage": "Confirm to exit the system?",
+            "menuLoading": "Menu loading..."
+        },
+        "errorLog": {
+            "tableTitle": "Error log list",
+            "tableColumnType": "Type",
+            "tableColumnDate": "Time",
+            "tableColumnFile": "File",
+            "tableColumnMsg": "Error message",
+            "tableColumnStackMsg": "Stack info",
+            "tableActionDesc": "Details",
+            "modalTitle": "Error details",
+            "fireVueError": "Fire vue error",
+            "fireResourceError": "Fire resource error",
+            "fireAjaxError": "Fire ajax error",
+            "enableMessage": "Only effective when useErrorHandle=true in `/src/settings/projectSetting.ts`."
+        },
+        "exception": {
+            "backLogin": "Back Login",
+            "backHome": "Back Home",
+            "subTitle403": "Sorry, you don't have access to this page.",
+            "subTitle404": "Sorry, the page you visited does not exist.",
+            "subTitle500": "Sorry, the server is reporting an error.",
+            "noDataTitle": "No data on the current page.",
+            "networkErrorTitle": "Network Error",
+            "networkErrorSubTitle": "Sorry,Your network connection has been disconnected, please check your network!"
+        },
+        "lock": {
+            "unlock": "Click to unlock",
+            "alert": "Lock screen password error",
+            "backToLogin": "Back to login",
+            "entry": "Enter the system",
+            "placeholder": "Please enter the lock screen password or user password"
+        },
+        "login": {
+            "backSignIn": "Back sign in",
+            "mobileSignInFormTitle": "Mobile sign in",
+            "qrSignInFormTitle": "Qr code sign in",
+            "signInFormTitle": "Sign in",
+            "signUpFormTitle": "Sign up",
+            "forgetFormTitle": "Reset password",
+            "signInTitle": "Backstage management system",
+            "signInDesc": "Enter your personal details and get started!",
+            "policy": "I agree to the xxx Privacy Policy",
+            "scanSign": "scanning the code to complete the login",
+            "loginButton": "Sign in",
+            "registerButton": "Sign up",
+            "rememberMe": "Remember me",
+            "forgetPassword": "Forget Password?",
+            "otherSignIn": "Sign in with",
+            "loginSuccessTitle": "Login successful",
+            "loginSuccessDesc": "Welcome back",
+            "accountPlaceholder": "Please input username",
+            "passwordPlaceholder": "Please input password",
+            "smsPlaceholder": "Please input sms code",
+            "mobilePlaceholder": "Please input mobile",
+            "policyPlaceholder": "Register after checking",
+            "diffPwd": "The two passwords are inconsistent",
+            "userName": "Username",
+            "password": "Password",
+            "confirmPassword": "Confirm Password",
+            "email": "Email",
+            "smsCode": "SMS code",
+            "mobile": "Mobile"
+        }
+    },
+    "routes": {
+        "account": {
+            "name": "User List",
+            "type": {
+                "1": "Privilege Order",
+                "2": "Download Order",
+                "3": "Purchase Order"
+            },
+            "detail": "Details",
+            "email": "User Email",
+            "id": "User ID",
+            "vip": "4DKanKan Member",
+            "yhgl": "User Overview",
+            "jbxx": "Basic Information",
+            "createTime": "Registration Time",
+            "yjcp": "Hardware Products",
+            "xjsl": "Number of Cameras",
+            "cjsl": "Number of Scenes",
+            "rjfw": "Software Services",
+            "zyhy": "Premium",
+            "gjhy": "Senior",
+            "xzcs": "Download Count",
+            "xzxz": "New Downloads",
+            "xzqy": "New Privileges",
+            "xjxq": "Camera Details",
+            "ckxq": "View Details",
+            "qyxq": "Privilege Details",
+            "xjlist": "View Camera List",
+            "jhshijian": "Activation Time",
+            "unbindTips": "Are you sure to unbind this camera!"
+        },
+        "basic": {
+            "login": "Login",
+            "errorLogList": "Error Log"
+        },
+        "count": {
+            "name1": "Prospective Users",
+            "name2": "Page Analysis",
+            "name": "User Name",
+            "email": "User Email",
+            "tel": "User Phone Number",
+            "company": "Company Name",
+            "submitTime": "Submission Time",
+            "submitLocation": "Submission Location",
+            "remarks": "Remarks",
+            "uuid": "Visit ID",
+            "sourceChannel": "Source Channel",
+            "qrCode": "QR Code",
+            "deviceType": "Device Type",
+            "mobile": "Mobile",
+            "computer": "Computer",
+            "pageDwellTime": "Page Dwell Time",
+            "scrollDepth": "Scroll Depth",
+            "visitTime": "Visit Time",
+            "visitAddress": "Visit Address",
+            "loadTime": "Load Time",
+            "networkType": "Network Type",
+            "browserLanguage": "Browser Language",
+            "lang": "English"
+        },
+        "dashboard": {
+            "dashboard": "Dashboard",
+            "about": "About",
+            "workbench": "Workbench",
+            "analysis": "Analysis",
+            "devices": "Equipment",
+            "equity": "Subscription",
+            "scene": "Scene",
+            "finance": "Sales Statistics",
+            "cameraScene": "Scene",
+            "loglist": "Operation Log",
+            "account": "User",
+            "retailer": "Reseller",
+            "overview": "User Overview",
+            "count": "UTM Data Analysis"
+        },
+        "demo": {
+            "charts": {
+                "baiduMap": "Baidu map",
+                "aMap": "A map",
+                "googleMap": "Google map",
+                "charts": "Chart",
+                "map": "Map",
+                "line": "Line",
+                "pie": "Pie"
+            },
+            "comp": {
+                "comp": "Component",
+                "basic": "Basic",
+                "transition": "Animation",
+                "countTo": "Count To",
+                "scroll": "Scroll",
+                "scrollBasic": "Basic",
+                "scrollAction": "Scroll Function",
+                "virtualScroll": "Virtual Scroll",
+                "tree": "Tree",
+                "treeBasic": "Basic",
+                "editTree": "Searchable/toolbar",
+                "actionTree": "Function operation",
+                "modal": "Modal",
+                "drawer": "Drawer",
+                "desc": "Desc",
+                "lazy": "Lazy",
+                "lazyBasic": "Basic",
+                "lazyTransition": "Animation",
+                "verify": "Verify",
+                "verifyDrag": "Drag ",
+                "verifyRotate": "Picture Restore",
+                "qrcode": "QR code",
+                "strength": "Password strength",
+                "upload": "Upload",
+                "loading": "Loading",
+                "time": "Relative Time",
+                "cropperImage": "Cropper Image",
+                "cardList": "Card List"
+            },
+            "editor": {
+                "editor": "Editor",
+                "jsonEditor": "Json editor",
+                "markdown": "Markdown editor",
+                "tinymce": "Rich text",
+                "tinymceBasic": "Basic",
+                "tinymceForm": "embedded form"
+            },
+            "excel": {
+                "excel": "Excel",
+                "customExport": "Select export format",
+                "jsonExport": "JSON data export",
+                "arrayExport": "Array data export",
+                "importExcel": "Import"
+            },
+            "feat": {
+                "feat": "Page Function",
+                "icon": "Icon",
+                "tabs": "Tabs",
+                "tabDetail": "Tab Detail",
+                "sessionTimeout": "Session Timeout",
+                "print": "Print",
+                "contextMenu": "Context Menu",
+                "download": "Download",
+                "clickOutSide": "ClickOutSide",
+                "imgPreview": "Picture Preview",
+                "copy": "Clipboard",
+                "msg": "Message prompt",
+                "watermark": "Watermark",
+                "ripple": "Ripple",
+                "fullScreen": "Full Screen",
+                "errorLog": "Error Log",
+                "tab": "Tab with parameters",
+                "tab1": "Tab with parameter 1",
+                "tab2": "Tab with parameter 2",
+                "menu": "Menu with parameters",
+                "menu1": "Menu with parameters 1",
+                "menu2": "Menu with parameters 2",
+                "ws": "Websocket test",
+                "breadcrumb": "Breadcrumbs",
+                "breadcrumbFlat": "Flat Mode",
+                "breadcrumbFlatDetail": "Flat mode details",
+                "breadcrumbChildren": "Level mode",
+                "breadcrumbChildrenDetail": "Level mode detail"
+            },
+            "flow": {
+                "name": "Graphics editor",
+                "flowChart": "FlowChart"
+            },
+            "form": {
+                "form": "Form",
+                "basic": "Basic",
+                "useForm": "useForm",
+                "refForm": "RefForm",
+                "advancedForm": "Shrinkable",
+                "ruleForm": "Form validation",
+                "dynamicForm": "Dynamic",
+                "customerForm": "Custom",
+                "appendForm": "Append"
+            },
+            "iframe": {
+                "frame": "External",
+                "antv": "antVue doc (embedded)",
+                "doc": "Project doc (embedded)",
+                "docExternal": "Project doc (external)"
+            },
+            "level": {
+                "level": "MultiMenu"
+            },
+            "page": {
+                "page": "Page",
+                "form": "Form",
+                "formBasic": "Basic Form",
+                "formStep": "Step Form",
+                "formHigh": "Advanced Form",
+                "desc": "Details",
+                "descBasic": "Basic Details",
+                "descHigh": "Advanced Details",
+                "result": "Result",
+                "resultSuccess": "Success",
+                "resultFail": "Failed",
+                "account": "Personal",
+                "accountCenter": "Personal Center",
+                "accountSetting": "Personal Settings",
+                "exception": "Exception",
+                "netWorkError": "Network Error",
+                "notData": "No data",
+                "list": "List page",
+                "listCard": "Card list",
+                "basic": "Basic list",
+                "listBasic": "Basic list",
+                "listSearch": "Search list"
+            },
+            "permission": {
+                "permission": "Permission",
+                "front": "front-end",
+                "frontPage": "Page",
+                "frontBtn": "Button",
+                "frontTestA": "Test page A",
+                "frontTestB": "Test page B",
+                "back": "background",
+                "backPage": "Page",
+                "backBtn": "Button"
+            },
+            "setup": {
+                "page": "Intro page"
+            },
+            "system": {
+                "moduleName": "System management",
+                "account": "Account management",
+                "account_detail": "Account detail",
+                "password": "Change password",
+                "dept": "Department management",
+                "menu": "Menu management",
+                "role": "Role management"
+            },
+            "table": {
+                "table": "Table",
+                "basic": "Basic",
+                "treeTable": "Tree",
+                "fetchTable": "Remote loading",
+                "fixedColumn": "Fixed column",
+                "customerCell": "Custom column",
+                "formTable": "Open search",
+                "useTable": "UseTable",
+                "refTable": "RefTable",
+                "multipleHeader": "MultiLevel header",
+                "mergeHeader": "Merge cells",
+                "expandTable": "Expandable table",
+                "fixedHeight": "Fixed height",
+                "footerTable": "Footer",
+                "editCellTable": "Editable cell",
+                "editRowTable": "Editable row",
+                "authColumn": "Auth column"
+            }
+        },
+        "device": {
+            "snCode": "S/N",
+            "wifiName": "Wifi",
+            "deviceType": "Camera type",
+            "activatedTime": "Deposit Time",
+            "userName": "Bound account",
+            "NoBind": "Unbind",
+            "export": "Export",
+            "type": {
+                "0": "4DKanKan Lite",
+                "1": "4DKanKan",
+                "2": "4DMinion",
+                "3": "4DMega",
+                "9": "4DMinion",
+                "10": "4DMega",
+                "11": "4DMeta"
+            },
+            "status": {
+                "0": "Active",
+                "1": "Expired",
+                "2": "Bind",
+                "3": "Unbind"
+            },
+            "bindStatus": "Binding status",
+            "statusName": "Status",
+            "incrementEndTime": "Expiry date",
+            "subAgentName": "Reseller"
+        },
+        "empower": {
+            "name": "Offline License",
+            "sq": "License",
+            "pldr": "Batch Import",
+            "pldrsuccess": "Import successful",
+            "pldrtips": "Download Batch Import Template",
+            "customerName": "End User Email Address",
+            "endCustomer": "End User Name",
+            "useTypeStr": "Usage Type",
+            "authorizeKey": "License Code",
+            "cameraSn": "Camera Sn",
+            "authorize": "License Code",
+            "authorizeTime": "License Duration",
+            "remark": "License Description",
+            "agentName": "Sub-Distributor Email Address",
+            "authorizeStartTime": "Start Date",
+            "authorizeEndTime": "End Date",
+            "agentId": "Sub-Distributor Email Address",
+            "addName": "Local Algorithm License",
+            "list": "Algorithm License List",
+            "deltTips": "Are you sure you want to delete this license?",
+            "addtTips": "Are you sure you want to add this license?",
+            "editTips": "Are you sure you want to edit this license?",
+            "remarks": "remark",
+            "placeholder": "Please enter the remarks information"
+        },
+        "equity": {
+            "add": "New Authorization",
+            "addDowm": "New Download",
+            "renew": "Renew",
+            "userName": "User Account",
+            "count": "User Account",
+            "orderSn": "Order Number",
+            "payTime": "Payment Time",
+            "invoiceTime": "Invoicing application time",
+            "money": "Invoiced Amount",
+            "id": "ID",
+            "dowmCount": "Download Time",
+            "timeList": "Authorization Time",
+            "expiryTime": "Expiry Date",
+            "newTime": "Latest Authorization Time",
+            "time": "Start Date",
+            "countNumber": " Quantity",
+            "Type": " Type",
+            "giveType": "Methods",
+            "orderSn1": "Transaction number",
+            "nickName": "Nickname",
+            "userName1": "Account",
+            "userCreateTime": "Registration time",
+            "email": "Email",
+            "userCount": "Authorized Quantity",
+            "incrementType": {
+                "0": "Membership Subscription",
+                "1": "Scene Download"
+            },
+            "equityType": {
+                "0": "Premium (Yearly)",
+                "1": "Premium (Yearly)",
+                "2": "Premium (Yearly)",
+                "3": "Senior (Monthly)"
+            },
+            "zhTips": "Chinese characters are not supported",
+            "listTitle": "Sales Statistics List",
+            "exportExcel": "Export to Excel",
+            "excelTitle": "Are you sure you want to export excel?",
+            "CardMajorNum": "Last Month's Premium Membership Sales (Yearly)",
+            "CardHighNum": "Last Month's Senior Membership Sales (Monthly)",
+            "CardDownNum": "Last Month's Download Sales",
+            "syks": "surplus",
+            "addcount": " Quantity",
+            "rules": {
+                "userName": "Please enter the user account",
+                "userName1": "Please enter the correct user account",
+                "userName2": "The account does not exist",
+                "id": "Please enter the correct benefit ID"
+            },
+            "unit": {
+                "1": "",
+                "2": "/Number of times",
+                "-1": "-Year",
+                "-2": "-Month",
+                "-3": "-Month"
+            },
+            "titleHelpMessage": {
+                "1": "Statistical Guidelines:",
+                "2": "Membership Subscription: current records of new authorizations by dealers and related ID renewal records, including dealer authorizations and renewals, platform authorizations (renewals), and official website purchases (renewals).",
+                "3": "Scene Download: statistical information on the number of downloads of current new authorizations by sales."
+            },
+            "totalTime": " Duration",
+            "totalMessge": "Insufficient Remaining Saleable Membership Subscriptions",
+            "operationType": "Operation",
+            "operationUserName": "User",
+            "operationTime": "Operation Time",
+            "incrementId": "Membership Subscription ID",
+            "platform": "Platform",
+            "operation": {
+                "0": "Authorize",
+                "1": "Deauthorize",
+                "2": "Bind",
+                "3": "Unbind"
+            },
+            "jjxs": "Upcoming sale"
+        },
+        "finance": {
+            "deptName": "Affiliated company",
+            "userName": "Full name",
+            "nickName": "Employee nickname",
+            "setpaswd": "Change Password",
+            "mobile": "Mobile phone",
+            "permList": "Equity",
+            "userId": "Account number",
+            "createTime": "Authorization Time",
+            "updateTime": "Modification Time",
+            "staffList": "Account List",
+            "updateBtn": "Change Password",
+            "password": "Change Password",
+            "agentName": "Authorizer",
+            "equityType": {
+                "0": "Premium (Yearly)",
+                "1": "Senior (Monthly)",
+                "2": "Scene Download"
+            },
+            "giveType": {
+                "0": "Dealer Authorization",
+                "1": "Dealer Renewals",
+                "2": "Official Website Purchase",
+                "3": "Platform Authorization",
+                "4": "Platform Purchase"
+            },
+            "totalTime": "Total duration of the authorization (year/month)"
+        },
+        "retailer": {
+            "name": "Reseller",
+            "add": "Add New Reseller",
+            "editfxs": "Edit Reseller",
+            "setName": "Membership Settings",
+            "nickName": "Contact",
+            "userName": "Please enter your 4DKanKan account",
+            "userId": "Account",
+            "tips": "This account does not exist",
+            "jxs": "Distributor",
+            "fxs": "Reseller",
+            "majorAddNum": "Premium Membership (Annual):  {value} years available for sale, newly added:",
+            "highAddNum": "Senior Membership (Monthly):  {value} months available for sale,  newly added:",
+            "downAddNum": "Project Downloads (Times):  {value} times available for sale, newly added:",
+            "ff": "Distribute",
+            "Unbind": "Unbind",
+            "UnbindTips": "Are you sure you want to unbind it?",
+            "allff": "Device Bulk Distribution",
+            "majorTotalNum": "Remaining Years of Premium Membership",
+            "highTotalNum": "Remaining Months of Senior Membership",
+            "downTotalNum": "Remaining Project Downloads",
+            "createName": "Creator",
+            "createTime": "Create Time",
+            "addjxs": "Add Dealer",
+            "editjxs": "Edit Dealer",
+            "activatedTime": "Equipment activation time",
+            "form": {
+                "name": " Reseller Name",
+                "nickName": "Contact",
+                "userName": "Please enter your 4DKanKan account",
+                "userId": "Account",
+                "tips": "This account does not exist",
+                "enable": "Enable",
+                "stopUsing": "Deactivate",
+                "dqname": "Reseller",
+                "d1name": "Distributor Name"
+            },
+            "exportText": "Successfully imported {value} pieces of data",
+            "device": {
+                "title": "Device Bulk Distribution",
+                "list": "Equipment List",
+                "dowmTips": "Download Distributor Device List Template",
+                "filename": "Reseller Device List Template"
+            }
+        },
+        "scene": {
+            "tableType": {
+                "0": "4DKanKan",
+                "1": "4DMinion",
+                "2": "4DMega Point Cloud",
+                "3": "4DKanKan Lite",
+                "5": "4DMega Mesh",
+                "6": "4DMeta Point Cloud",
+                "7": "4DMeta Mesh"
+            },
+            "transfer": "transfer",
+            "copy": "copy",
+            "down": "download",
+            "canlenDown": "Cancel Download",
+            "sceneName": "Scene Title",
+            "num": "Scene Code",
+            "createTime": "Shooting Time",
+            "amount": "Calculation Completion Time",
+            "snCode": "SN",
+            "sceneSize": "Scene Size",
+            "userName": "Bound account",
+            "viewCount": "Views",
+            "status": "Status",
+            "copyTime": "Scene Copied Time",
+            "isCopy": "Copied scene",
+            "statusType": {
+                "0": "In calculation",
+                "1": "Calculation succeeded",
+                "-2": "Calculation succeeded",
+                "-1": "Calculation failed",
+                "-3": "Sealing"
+            },
+            "copyTipsTitle": "Copy Scene",
+            "copyTipsText": "Copy the scene, and the scene belongs to the original camera<br/>Are you sure you want to copy the scene?",
+            "copySccuse": "Copy succeeded",
+            "deleteSccuse": "Deletion succeeded",
+            "downErr": "Download failed",
+            "transferSccuse": "Scenario migration succeeded.",
+            "transferTitle": "Migration Scenario",
+            "toSnCode": "Migrate to",
+            "reset": "rerun",
+            "resetTips": "Confirm to recalculate?",
+            "rules": {
+                "snCode": "Please enter the SN code of the camera",
+                "snCode1": "Chinese characters are not supported"
+            }
+        }
     }
   },
   "common": {

+ 3 - 3
src/router/routes/modules/account.ts

@@ -13,7 +13,7 @@ export const Device: AppRouteRecordRaw = {
     icon: 'uil:user-md',
     orderNo: 6,
     hideChildrenInMenu: true,
-    roles: [RoleEnum.SUPER, RoleEnum.TEST],
+    // roles: [RoleEnum.SUPER, RoleEnum.TEST],
   },
   children: [
     {
@@ -23,7 +23,7 @@ export const Device: AppRouteRecordRaw = {
       meta: {
         title: t('routes.dashboard.account'),
         hideBreadcrumb: true,
-        roles: [RoleEnum.SUPER, RoleEnum.TEST],
+        // roles: [RoleEnum.SUPER, RoleEnum.TEST],
       },
     },
     {
@@ -33,7 +33,7 @@ export const Device: AppRouteRecordRaw = {
       meta: {
         title: t('routes.dashboard.account'),
         hideBreadcrumb: true,
-        roles: [RoleEnum.SUPER, RoleEnum.TEST],
+        // roles: [RoleEnum.SUPER, RoleEnum.TEST],
       },
     },
   ],

+ 2 - 2
src/router/routes/modules/count.ts

@@ -13,7 +13,7 @@ export const LoglistRoute: AppRouteRecordRaw = {
     icon: 'wpf:statistics',
     orderNo: 11,
     hideChildrenInMenu: true,
-    roles: [RoleEnum.SUPER, RoleEnum.TEST, RoleEnum.LEVEL2s],
+    // roles: [RoleEnum.SUPER, RoleEnum.TEST, RoleEnum.LEVEL2s],
   },
   children: [
     {
@@ -23,7 +23,7 @@ export const LoglistRoute: AppRouteRecordRaw = {
       meta: {
         title: t('routes.dashboard.count'),
         hideBreadcrumb: true,
-        roles: [RoleEnum.SUPER, RoleEnum.TEST, RoleEnum.LEVEL2s],
+        // roles: [RoleEnum.SUPER, RoleEnum.TEST, RoleEnum.LEVEL2s],
       },
     },
   ],

+ 126 - 5
src/views/account/lists.vue

@@ -1,5 +1,8 @@
 <template>
   <BasicTable @register="registerTimeTable">
+    <template #toolbar>
+      <a-button type="primary" @click="handleExport">{{ t('routes.equity.exportExcel') }}</a-button>
+    </template>
     <template #action="{ record }">
       <TableAction
         :actions="[
@@ -23,6 +26,9 @@
   import { otherInfoStore } from '/@/store/modules/other';
   import { usePermissionStore } from '/@/store/modules/permission';
   import { useUserStore } from '/@/store/modules/user';
+  import { useMessage } from '/@/hooks/web/useMessage';
+  import { formatToDateTime } from '/@/utils/dateUtil';
+  import * as XLSX from 'xlsx-js-style';
   export default defineComponent({
     components: {
       BasicTable,
@@ -37,6 +43,19 @@
       const isDev = computed(() => userStore.getSystemEnv);
       const permissionStore = usePermissionStore();
       const { getCheckPerm } = permissionStore;
+      const { createMessage } = useMessage();
+
+      function buildSearchParams(params: Recordable = {}) {
+        const searchParams = { ...params };
+        const timeList = searchParams.timeList || [];
+        delete searchParams.timeList;
+        return {
+          ...searchParams,
+          userCreateTimeStart: timeList[0],
+          userCreateTimeEnd: timeList[1],
+        };
+      }
+
       const searchForm: Partial<FormProps> = {
         labelWidth: 100,
         schemas: [
@@ -46,10 +65,13 @@
             component: 'Input',
             componentProps: {
               maxLength: 100,
+              style: {
+                width: '150px',
+              },
             },
             colProps: {
-              xl: 6,
-              xxl: 6,
+              xl: 4,
+              xxl: 4,
             },
           },
           {
@@ -59,15 +81,31 @@
             ifShow: !isDev.value,
             componentProps: {
               maxLength: 100,
+              style: {
+                width: '200px',
+              },
             },
             colProps: {
-              xl: 8,
-              xxl: 8,
+              xl: 6,
+              xxl: 6,
+            },
+          },
+          {
+            field: 'timeList',
+            label: t('routes.equity.userCreateTime'),
+            component: 'RangePicker',
+            componentProps: {
+              valueFormat: 'YYYY-MM-DD',
+              format: 'YYYY-MM-DD',
+            },
+            colProps: {
+              xl: 10,
+              xxl: 10,
             },
           },
         ],
       };
-      const [registerTimeTable, { reload }] = useTable({
+      const [registerTimeTable, { reload, getDataSource }] = useTable({
         api: ListApi,
         title: t('routes.account.name'),
         columns: userListSchema,
@@ -76,6 +114,7 @@
         showTableSetting: true,
         showIndexColumn: false,
         rowKey: 'id',
+        beforeFetch: buildSearchParams,
         fetchSetting: {
           pageField: 'pageNum',
           sizeField: 'pageSize',
@@ -102,12 +141,94 @@
         setOverviewInfo(record);
         router.push({ path: 'details' });
       }
+
+      async function handleExport() {
+        try {
+          const exportList = getDataSource<Recordable>() || [];
+
+          const headerList = [
+            t('routes.account.id'),
+            t('routes.equity.nickName'),
+            t('routes.equity.userName1'),
+            t('routes.equity.userCreateTime'),
+            t('routes.account.vip'),
+          ];
+
+          const data = exportList.map((item) => [
+            item.id ?? '-',
+            item.nickName || '-',
+            item.userName || '-',
+            item.createTime ? formatToDateTime(item.createTime) : '-',
+            item.vip == 0 ? t('common.no') : t('common.yes'),
+          ]);
+
+          const worksheet = XLSX.utils.aoa_to_sheet([headerList, ...data]);
+          worksheet['!cols'] = [{ wch: 12 }, { wch: 18 }, { wch: 22 }, { wch: 24 }, { wch: 18 }];
+
+          const headerStyle = {
+            font: {
+              name: '宋体',
+              sz: 14,
+              bold: true,
+            },
+            fill: {
+              patternType: 'solid',
+              fgColor: { rgb: 'C0C0C0' },
+            },
+            alignment: {
+              horizontal: 'center',
+              vertical: 'center',
+              wrapText: true,
+            },
+            border: {
+              top: { style: 'thin', color: { rgb: '000000' } },
+              bottom: { style: 'thin', color: { rgb: '000000' } },
+              left: { style: 'thin', color: { rgb: '000000' } },
+              right: { style: 'thin', color: { rgb: '000000' } },
+            },
+          };
+          const dataCellStyle = {
+            alignment: {
+              horizontal: 'center',
+              vertical: 'center',
+            },
+          };
+
+          headerList.forEach((_, index) => {
+            const cellAddress = XLSX.utils.encode_cell({ r: 0, c: index });
+            if (worksheet[cellAddress]) {
+              worksheet[cellAddress].s = headerStyle as any;
+            }
+          });
+          data.forEach((row, rowIndex) => {
+            row.forEach((_, colIndex) => {
+              const cellAddress = XLSX.utils.encode_cell({ r: rowIndex + 1, c: colIndex });
+              if (worksheet[cellAddress]) {
+                worksheet[cellAddress].s = dataCellStyle as any;
+              }
+            });
+          });
+
+          const sheetName = t('routes.account.name');
+          const workbook = {
+            SheetNames: [sheetName],
+            Sheets: {
+              [sheetName]: worksheet,
+            },
+          };
+          XLSX.writeFile(workbook, `${Date.now()}${t('routes.dashboard.account')}.xlsx`);
+          createMessage.success(t('common.optSuccess'));
+        } catch (error) {
+          console.log('export user list failed', error);
+        }
+      }
       return {
         registerTimeTable,
         handleOpen,
         tabChange,
         reload,
         handleEdit,
+        handleExport,
         getCheckPerm,
         t,
       };

+ 11 - 2
src/views/count/index.vue

@@ -35,7 +35,7 @@
   import { dincrementList, cameraIncrementLog } from '/@/api/equity';
   import { contactUsList, pointList, DownCountExport1, DownCountExport2 } from '/@/api/finance';
   import { useLocaleStore } from '/@/store/modules/locale';
-  import { columns1, columns } from './data'
+  import { columns1, columns } from './data';
   import { useMessage } from '/@/hooks/web/useMessage';
   export default defineComponent({
     components: {
@@ -82,9 +82,18 @@
               xxl: 7,
             },
           },
+          {
+            field: 'country',
+            component: 'Input',
+            label: t('routes.count.submitLocation'),
+            colProps: {
+              xl: 7,
+              xxl: 7,
+            },
+          },
         ],
       };
-      
+
       const searchForm: Partial<FormProps> = {
         labelWidth: 120,
         autoAdvancedLine: 1,

+ 63 - 5
src/views/device/index.vue

@@ -5,7 +5,13 @@
         <template #toolbar>
           <a-button
             v-if="
-              hasPermission([RoleEnum.SUPER, RoleEnum.TEST, RoleEnum.LEVEL2, RoleEnum.LEVEL2s, RoleEnum.DISTRIBUTOR])
+              hasPermission([
+                RoleEnum.SUPER,
+                RoleEnum.TEST,
+                RoleEnum.LEVEL2,
+                RoleEnum.LEVEL2s,
+                RoleEnum.DISTRIBUTOR,
+              ])
             "
             @click="getTemplate"
           >
@@ -41,6 +47,7 @@
       </BasicTable>
     </div>
     <distributeModal @reload="reload" @register="registerAddModal" />
+    <subAgentInfoModal @register="registerSubAgentInfoModal" />
   </PageWrapper>
 </template>
 <script lang="ts">
@@ -70,14 +77,18 @@
   import { dincrementList } from '/@/api/equity';
   import { useUserStore } from '/@/store/modules/user';
   import { downCameraExport } from '/@/api/customer';
+  import { Icon } from '/@/components/Icon';
   import distributeModal from './distributeModal.vue';
+  import subAgentInfoModal from './subAgentInfoModal.vue';
   export default defineComponent({
     components: {
       BasicTable,
       TableAction,
       PageWrapper,
       TableImg,
+      Icon,
       distributeModal,
+      subAgentInfoModal,
       [Descriptions.name]: Descriptions,
       [Descriptions.Item.name]: Descriptions.Item,
     },
@@ -94,6 +105,10 @@
       const isEn = computed(() => localeStore.getLocale === 'en');
       const companyId: Number = router.currentRoute.value.params.id - 0;
       const [registerAddModal, { openModal }] = useModal();
+      const [registerSubAgentInfoModal, { openModal: openSubAgentInfoModal }] = useModal();
+      const subAgentInfoText = computed(() =>
+        isEn.value ? 'Distribution Log' : '\u5206\u914d\u65e5\u5fd7',
+      );
       onMounted(() => {
         // console.log(router.currentRoute.value.params.id);
       });
@@ -134,11 +149,28 @@
         {
           title: t('routes.retailer.fxs'),
           dataIndex: 'subAgentName',
-          ellipsis: true,
-          width: 160,
+          ellipsis: false,
+          width: 240,
           // ifShow: hasPermission([RoleEnum.SUPER]),
           customRender({ record }) {
-            return record.subAgentName || '-';
+            if (!record.subAgentName) {
+              return '-';
+            }
+            return h('div', { class: 'sub-agent-cell' }, [
+              h('span', { class: 'sub-agent-name' }, record.subAgentName),
+              h(
+                'a',
+                {
+                  class: 'sub-agent-info-link',
+                  title: subAgentInfoText.value,
+                  onClick: (event) => {
+                    event.stopPropagation();
+                    handleViewSubAgentInfo(record);
+                  },
+                },
+                [h(Icon, { icon: 'ion:information-circle-outline', size: 16 })],
+              ),
+            ]);
           },
         },
         {
@@ -413,7 +445,7 @@
       async function getTemplate() {
         const lang = locale.value == 'zh_CN' ? 'zh' : 'en';
         try {
-          const res = await downCameraExport({lang});
+          const res = await downCameraExport({ lang });
         } catch (error) {
           console.log('not passing', error);
         }
@@ -425,6 +457,9 @@
       function headleDetails(record: Recordable) {
         openModal(true, record);
       }
+      function handleViewSubAgentInfo(record: Recordable) {
+        openSubAgentInfoModal(true, record);
+      }
       return {
         getTemplate,
         registerTable,
@@ -435,6 +470,7 @@
         handleAdd,
         headleDetails,
         registerAddModal,
+        registerSubAgentInfoModal,
         hasPermission,
         RoleEnum,
         t,
@@ -449,4 +485,26 @@
       padding: 0;
     }
   }
+
+  :deep(.sub-agent-cell) {
+    display: inline-flex;
+    max-width: 100%;
+    align-items: center;
+    gap: 10px;
+  }
+
+  :deep(.sub-agent-name) {
+    overflow: hidden;
+    min-width: 0;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+  }
+
+  :deep(.sub-agent-info-link) {
+    flex: none;
+    white-space: nowrap;
+    display: inline-flex;
+    align-items: center;
+    justify-content: center;
+  }
 </style>

+ 108 - 0
src/views/device/subAgentInfoModal.vue

@@ -0,0 +1,108 @@
+<template>
+  <BasicModal
+    v-bind="$attrs"
+    @register="register"
+    :title="modalTitle"
+    :showOkBtn="false"
+    :showCancelBtn="false"
+    :footer="null"
+    width="760px"
+  >
+    <div class="pt-3px pr-3px">
+      <BasicTable @register="registerTable" />
+    </div>
+  </BasicModal>
+</template>
+<script lang="ts">
+  import { computed, defineComponent, h, reactive } from 'vue';
+  import { BasicModal, useModalInner } from '/@/components/Modal';
+  import { BasicTable, BasicColumn, useTable } from '/@/components/Table';
+  import { Time } from '/@/components/Time';
+  import { useI18n } from '/@/hooks/web/useI18n';
+  import { useLocaleStore } from '/@/store/modules/locale';
+  import { getGiveCamLog } from '/@/api/device';
+
+  export default defineComponent({
+    components: {
+      BasicModal,
+      BasicTable,
+    },
+    setup() {
+      const { t } = useI18n();
+      const localeStore = useLocaleStore();
+      const queryParams = reactive<Recordable>({
+        id: undefined,
+        cameraId: undefined,
+        snCode: '',
+      });
+
+      const modalTitle = computed(() =>
+        localeStore.getLocale === 'en' ? 'Distribution Log' : '分配日志',
+      );
+
+      const columns: BasicColumn[] = [
+        {
+          title: t('routes.retailer.jxs'),
+          dataIndex: 'agentName',
+          width: 220,
+          customRender: ({ record }) => record.agentName || record.subAgentName || '-',
+        },
+        {
+          title: t('routes.finance.updateTime'),
+          dataIndex: 'updateTime',
+          width: 220,
+          customRender: ({ record }) => {
+            const time = record.updateTime || record.createTime;
+            return time
+              ? h(Time, {
+                  value: time,
+                  mode: 'datetime',
+                })
+              : '-';
+          },
+        },
+      ];
+
+      const [registerTable, { reload }] = useTable({
+        api: getGiveCamLog,
+        columns,
+        immediate: false,
+        autoCreateKey: true,
+        searchInfo: queryParams,
+        showIndexColumn: true,
+        indexColumnProps: {
+          title: localeStore.getLocale === 'en' ? 'No.' : '\u5e8f\u5217',
+          width: 70,
+        },
+        showTableSetting: false,
+        canResize: false,
+        bordered: true,
+        fetchSetting: {
+          pageField: 'pageNum',
+          sizeField: 'pageSize',
+          listField: 'list',
+          totalField: 'total',
+        },
+      });
+
+      const [register, { changeLoading }] = useModalInner(async (data) => {
+        queryParams.id = data?.id;
+        queryParams.cameraId = data?.id;
+        queryParams.snCode = data?.snCode || '';
+
+        changeLoading(true);
+        try {
+          await reload({ page: 1 });
+        } finally {
+          changeLoading(false);
+        }
+      });
+
+      return {
+        modalTitle,
+        register,
+        registerTable,
+      };
+    },
+  });
+</script>

+ 16 - 2
src/views/empower/AddModal.vue

@@ -25,6 +25,7 @@
   import { incrementUseTypeList } from '/@/api/account';
   import { useUserStore } from '/@/store/modules/user';
   import { getSubAgent } from '/@/api/retailer';
+  import { RoleEnum } from '/@/enums/roleEnum';
 
   const { t } = useI18n();
   export default defineComponent({
@@ -37,6 +38,12 @@
       // const otherInfo = otherInfoStore();
       const userStore = useUserStore();
       const agent = computed(() => userStore.getAgent);
+      const canEditAuthorizeKey = computed(() => {
+        const roleList = userStore.getRoleList || [];
+        return !roleList.some((role) =>
+          [RoleEnum.LEVEL2, RoleEnum.LEVEL2s, RoleEnum.DISTRIBUTOR].includes(role),
+        );
+      });
       // const overviewInfo = computed(() => otherInfo.getOverviewInfo);
       // const overviewInfo = getOverviewInfo() || {}
       const fileFlow = reactive({
@@ -241,6 +248,12 @@
         fileFlow.id = data.id;
         updateSchema([
           {
+            field: 'authorizeKey',
+            componentProps: {
+              disabled: !!data.id && !canEditAuthorizeKey.value,
+            },
+          },
+          {
             field: 'useType',
             componentProps: {
               // onChange: (value) => {
@@ -253,7 +266,7 @@
           //   ifShow: data.useType == '4',
           // },
         ]);
-        data.authorizeTime = [data.authorizeStartTime, data.authorizeEndTime]
+        data.authorizeTime = [data.authorizeStartTime, data.authorizeEndTime];
         setFieldsValue(data);
       }
       async function handleConfirm() {
@@ -261,7 +274,8 @@
         createConfirm({
           iconType: 'warning',
           title: () => h('span', t('common.reminder')),
-          content: () => h('span',  id ? t('routes.empower.editTips') : t('routes.empower.addtTips'),),
+          content: () =>
+            h('span', id ? t('routes.empower.editTips') : t('routes.empower.addtTips')),
           onOk: async () => {
             handleSubmit();
           },