Commit 9719c73e by huangqy

提交整个

parents
---
name: 🐞 Bug report
about: Create a report to help us improve
title: "[Bug] the title of bug report"
labels: bug
assignees: ''
---
#### Describe the bug
---
name: 🥺 Help wanted
about: Confuse about the use of electron-vue-vite
title: "[Help] the title of help wanted report"
labels: help wanted
assignees: ''
---
#### Describe the problem you confuse
<!-- Thank you for contributing! -->
### Description
<!-- Please insert your description here and provide especially info about the "what" this PR is solving -->
### What is the purpose of this pull request? <!-- (put an "X" next to an item) -->
- [ ] Bug fix
- [ ] New Feature
- [ ] Documentation update
- [ ] Other
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: "npm" # See documentation for possible values
directory: "/" # Location of package manifests
schedule:
interval: "monthly"
name: Build
on:
push:
branches: [main]
paths-ignore:
- "**.md"
- "**.spec.js"
- ".idea"
- ".vscode"
- ".dockerignore"
- "Dockerfile"
- ".gitignore"
- ".github/**"
- "!.github/workflows/build.yml"
jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [macos-latest, ubuntu-latest, windows-latest]
steps:
- name: Checkout Code
uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: 18
- name: Install Dependencies
run: npm install
- name: Build Release Files
run: npm run build
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Upload Artifact
uses: actions/upload-artifact@v3
with:
name: release_on_${{ matrix. os }}
path: release/
retention-days: 5
\ No newline at end of file
name: CI
on:
pull_request_target:
branches:
- main
permissions:
pull-requests: write
jobs:
job1:
name: Check Not Allowed File Changes
runs-on: ubuntu-latest
outputs:
markdown_change: ${{ steps.filter_markdown.outputs.change }}
markdown_files: ${{ steps.filter_markdown.outputs.change_files }}
steps:
- name: Check Not Allowed File Changes
uses: dorny/paths-filter@v2
id: filter_not_allowed
with:
list-files: json
filters: |
change:
- 'package-lock.json'
- 'yarn.lock'
- 'pnpm-lock.yaml'
# ref: https://github.com/github/docs/blob/main/.github/workflows/triage-unallowed-contributions.yml
- name: Comment About Changes We Can't Accept
if: ${{ steps.filter_not_allowed.outputs.change == 'true' }}
uses: actions/github-script@v6
with:
script: |
let workflowFailMessage = "It looks like you've modified some files that we can't accept as contributions."
try {
const badFilesArr = [
'package-lock.json',
'yarn.lock',
'pnpm-lock.yaml',
]
const badFiles = badFilesArr.join('\n- ')
const reviewMessage = `👋 Hey there spelunker. It looks like you've modified some files that we can't accept as contributions. The complete list of files we can't accept are:\n- ${badFiles}\n\nYou'll need to revert all of the files you changed in that list using [GitHub Desktop](https://docs.github.com/en/free-pro-team@latest/desktop/contributing-and-collaborating-using-github-desktop/managing-commits/reverting-a-commit) or \`git checkout origin/main <file name>\`. Once you get those files reverted, we can continue with the review process. :octocat:\n\nMore discussion:\n- https://github.com/electron-vite/electron-vite-vue/issues/192`
createdComment = await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.number,
body: reviewMessage,
})
workflowFailMessage = `${workflowFailMessage} Please see ${createdComment.data.html_url} for details.`
} catch(err) {
console.log("Error creating comment.", err)
}
core.setFailed(workflowFailMessage)
- name: Check Not Linted Markdown
if: ${{ always() }}
uses: dorny/paths-filter@v2
id: filter_markdown
with:
list-files: shell
filters: |
change:
- added|modified: '*.md'
job2:
name: Lint Markdown
runs-on: ubuntu-latest
needs: job1
if: ${{ always() && needs.job1.outputs.markdown_change == 'true' }}
steps:
- name: Checkout Code
uses: actions/checkout@v3
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Lint markdown
run: npx markdownlint-cli ${{ needs.job1.outputs.markdown_files }} --ignore node_modules
\ No newline at end of file
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
dist-electron
release
*.local
# Editor directories and files
.vscode/.debug.env
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
# lockfile
package-lock.json
pnpm-lock.yaml
yarn.lock
\ No newline at end of file
import fs from 'node:fs'
import path from 'node:path'
import { fileURLToPath } from 'node:url'
import { createRequire } from 'node:module'
import { spawn } from 'node:child_process'
const pkg = createRequire(import.meta.url)('../package.json')
const __dirname = path.dirname(fileURLToPath(import.meta.url))
// write .debug.env
const envContent = Object.entries(pkg.debug.env).map(([key, val]) => `${key}=${val}`)
fs.writeFileSync(path.join(__dirname, '.debug.env'), envContent.join('\n'))
// bootstrap
spawn(
// TODO: terminate `npm run dev` when Debug exits.
process.platform === 'win32' ? 'npm.cmd' : 'npm',
['run', 'dev'],
{
stdio: 'inherit',
env: Object.assign(process.env, { VSCODE_DEBUG: 'true' }),
},
)
{
"recommendations": [
"Vue.volar",
"Vue.vscode-typescript-vue-plugin"
]
}
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"compounds": [
{
"name": "Debug App",
"preLaunchTask": "Before Debug",
"configurations": [
"Debug Main Process",
"Debug Renderer Process"
],
"presentation": {
"hidden": false,
"group": "",
"order": 1
},
"stopAll": true
}
],
"configurations": [
{
"name": "Debug Main Process",
"type": "node",
"request": "launch",
"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron",
"windows": {
"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron.cmd"
},
"runtimeArgs": [
"--remote-debugging-port=9229",
"."
],
"envFile": "${workspaceFolder}/.vscode/.debug.env",
"console": "integratedTerminal"
},
{
"name": "Debug Renderer Process",
"port": 9229,
"request": "attach",
"type": "chrome",
"timeout": 60000,
"skipFiles": [
"<node_internals>/**",
"${workspaceRoot}/node_modules/**",
"${workspaceRoot}/dist-electron/**",
// Skip files in host(VITE_DEV_SERVER_URL)
"http://127.0.0.1:3344/**"
]
},
]
}
{
"typescript.tsdk": "node_modules/typescript/lib",
"typescript.tsc.autoDetect": "off",
"json.schemas": [
{
"fileMatch": [
"/*electron-builder.json5",
"/*electron-builder.json"
],
"url": "https://json.schemastore.org/electron-builder"
}
]
}
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "Before Debug",
"type": "shell",
"command": "node .vscode/.debug.script.mjs",
"isBackground": true,
"problemMatcher": {
"owner": "typescript",
"fileLocation": "relative",
"pattern": {
// TODO: correct "regexp"
"regexp": "^([a-zA-Z]\\:\/?([\\w\\-]\/?)+\\.\\w+):(\\d+):(\\d+): (ERROR|WARNING)\\: (.*)$",
"file": 1,
"line": 3,
"column": 4,
"code": 5,
"message": 6
},
"background": {
"activeOnStart": true,
"beginsPattern": "^.*VITE v.* ready in \\d* ms.*$",
"endsPattern": "^.*\\[startup\\] Electron App.*$"
}
}
}
]
}
## 2022-10-03
[v2.1.0](https://github.com/electron-vite/electron-vite-vue/pull/267)
- `vite-electron-plugin` is Fast, and WYSIWYG. 🌱
- last-commit: db2e830 v2.1.0: use `vite-electron-plugin` instead `vite-plugin-electron`
## 2022-06-04
[v2.0.0](https://github.com/electron-vite/electron-vite-vue/pull/156)
- 🖖 Based on the `vue-ts` template created by `npm create vite`, integrate `vite-plugin-electron`
- ⚡️ More simplify, is in line with Vite project structure
- last-commit: a15028a (HEAD -> main) feat: hoist `process.env`
## 2022-01-30
[v1.0.0](https://github.com/electron-vite/electron-vite-vue/releases/tag/v1.0.0)
- ⚡️ Main、Renderer、preload, all built with vite
## 2022-01-27
- Refactor the scripts part.
- Remove `configs` directory.
## 2021-11-11
- Refactor the project. Use vite.config.ts build `Main-process`, `Preload-script` and `Renderer-process` alternative rollup.
- Scenic `Vue>=3.2.13`, `@vue/compiler-sfc` is no longer necessary.
- If you prefer Rollup, Use rollup branch.
```bash
Error: @vitejs/plugin-vue requires vue (>=3.2.13) or @vue/compiler-sfc to be present in the dependency tree.
```
MIT License
Copyright (c) 2020 草鞋没号
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
# electron-vite-vue
🥳 Really simple `Electron` + `Vue` + `Vite` boilerplate.
<!-- [![awesome-vite](https://awesome.re/mentioned-badge.svg)](https://github.com/vitejs/awesome-vite) -->
<!-- [![Netlify Status](https://api.netlify.com/api/v1/badges/ae3863e3-1aec-4eb1-8f9f-1890af56929d/deploy-status)](https://app.netlify.com/sites/electron-vite/deploys) -->
<!-- [![GitHub license](https://img.shields.io/github/license/caoxiemeihao/electron-vite-vue)](https://github.com/electron-vite/electron-vite-vue/blob/main/LICENSE) -->
<!-- [![GitHub stars](https://img.shields.io/github/stars/caoxiemeihao/electron-vite-vue?color=fa6470)](https://github.com/electron-vite/electron-vite-vue) -->
<!-- [![GitHub forks](https://img.shields.io/github/forks/caoxiemeihao/electron-vite-vue)](https://github.com/electron-vite/electron-vite-vue) -->
[![GitHub Build](https://github.com/electron-vite/electron-vite-vue/actions/workflows/build.yml/badge.svg)](https://github.com/electron-vite/electron-vite-vue/actions/workflows/build.yml)
[![GitHub Discord](https://img.shields.io/badge/chat-discord-blue?logo=discord)](https://discord.gg/sRqjYpEAUK)
## Features
📦 Out of the box
🎯 Based on the official [template-vue-ts](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-vue-ts), less invasive
🌱 Extensible, really simple directory structure
💪 Support using Node.js API in Electron-Renderer
🔩 Support C/C++ native addons
🖥 It's easy to implement multiple windows
## Quick Start
```sh
npm create electron-vite
```
<!-- [![quick-start](https://asciinema.org/a/483731.svg)](https://asciinema.org/a/483731) -->
![electron-vite-vue.gif](/public/electron-vite-vue.gif)
## Debug
![electron-vite-react-debug.gif](https://github.com/electron-vite/electron-vite-react/blob/main/public/electron-vite-react-debug.gif?raw=true)
## Directory
```diff
+ ├─┬ electron
+ │ ├─┬ main
+ │ │ └── index.ts entry of Electron-Main
+ │ └─┬ preload
+ │ └── index.ts entry of Preload-Scripts
├─┬ src
│ └── main.ts entry of Electron-Renderer
├── index.html
├── package.json
└── vite.config.ts
```
## Be aware
🚨 By default, this template integrates Node.js in the Renderer process. If you don't need it, you just remove the option below. [Because it will modify the default config of Vite](https://github.com/electron-vite/vite-plugin-electron-renderer#config-presets-opinionated).
```diff
# vite.config.ts
export default {
plugins: [
- // Use Node.js API in the Renderer-process
- renderer({
- nodeIntegration: true,
- }),
],
}
```
## FAQ
- [dependencies vs devDependencies](https://github.com/electron-vite/vite-plugin-electron-renderer#dependencies-vs-devdependencies)
- [C/C++ addons, Node.js modules - Pre-Bundling](https://github.com/electron-vite/vite-plugin-electron-renderer#dependency-pre-bundling)
/**
* @see https://www.electron.build/configuration/configuration
*/
{
"appId": "YourAppID",
"asar": true,
"icon": "public/favicon.ico",
"directories": {
"output": "release/${version}"
},
"files": [
"dist-electron",
"dist"
],
"mac": {
"artifactName": "${productName}_${version}.${ext}",
"target": [
"dmg"
]
},
"win": {
"target": [
{
"target": "nsis",
"arch": [
"x64"
]
}
],
"artifactName": "${productName}_${version}.${ext}"
},
"nsis": {
"oneClick": false,
"perMachine": false,
"allowToChangeInstallationDirectory": true,
"deleteAppDataOnUninstall": false
}
}
/// <reference types="vite-plugin-electron/electron-env" />
declare namespace NodeJS {
interface ProcessEnv {
VSCODE_DEBUG?: 'true'
DIST_ELECTRON: string
DIST: string
/** /dist/ or /public/ */
PUBLIC: string
}
}
import { app, BrowserWindow, shell, ipcMain } from 'electron'
import { release } from 'node:os'
import { join } from 'node:path'
// The built directory structure
//
// ├─┬ dist-electron
// │ ├─┬ main
// │ │ └── index.js > Electron-Main
// │ └─┬ preload
// │ └── index.js > Preload-Scripts
// ├─┬ dist
// │ └── index.html > Electron-Renderer
//
process.env.DIST_ELECTRON = join(__dirname, '..')
process.env.DIST = join(process.env.DIST_ELECTRON, '../dist')
process.env.PUBLIC = process.env.VITE_DEV_SERVER_URL
? join(process.env.DIST_ELECTRON, '../public')
: process.env.DIST
// Disable GPU Acceleration for Windows 7
if (release().startsWith('6.1')) app.disableHardwareAcceleration()
// Set application name for Windows 10+ notifications
if (process.platform === 'win32') app.setAppUserModelId(app.getName())
if (!app.requestSingleInstanceLock()) {
app.quit()
process.exit(0)
}
// Remove electron security warnings
// This warning only shows in development mode
// Read more on https://www.electronjs.org/docs/latest/tutorial/security
// process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = 'true'
let win: BrowserWindow | null = null
// Here, you can also use other preload
const preload = join(__dirname, '../preload/index.js')
const url = process.env.VITE_DEV_SERVER_URL
const indexHtml = join(process.env.DIST, 'index.html')
async function createWindow() {
win = new BrowserWindow({
title: 'Main window',
// frame: true,
fullscreen: false,
icon: join(process.env.PUBLIC, 'favicon.ico'),
webPreferences: {
preload,
// Warning: Enable nodeIntegration and disable contextIsolation is not secure in production
// Consider using contextBridge.exposeInMainWorld
// Read more on https://www.electronjs.org/docs/latest/tutorial/context-isolation
nodeIntegration: true,
contextIsolation: false,
},
})
if (process.env.VITE_DEV_SERVER_URL) { // electron-vite-vue#298
win.loadURL(url)
// Open devTool if the app is not packaged
win.webContents.openDevTools()
} else {
win.loadFile(indexHtml)
}
// Test actively push message to the Electron-Renderer
win.webContents.on('did-finish-load', () => {
win?.webContents.send('main-process-message', new Date().toLocaleString())
})
// Make all links open with the browser, not with the application
win.webContents.setWindowOpenHandler(({ url }) => {
if (url.startsWith('https:')) shell.openExternal(url)
return { action: 'deny' }
})
}
app.whenReady().then(createWindow)
app.on('window-all-closed', () => {
win = null
if (process.platform !== 'darwin') app.quit()
})
app.on('second-instance', () => {
if (win) {
// Focus on the main window if the user tried to open another
if (win.isMinimized()) win.restore()
win.focus()
}
})
app.on('activate', () => {
const allWindows = BrowserWindow.getAllWindows()
if (allWindows.length) {
allWindows[0].focus()
} else {
createWindow()
}
})
// New window example arg: new windows url
ipcMain.handle('open-win', (_, arg) => {
const childWindow = new BrowserWindow({
webPreferences: {
preload,
nodeIntegration: true,
contextIsolation: false,
},
})
if (process.env.VITE_DEV_SERVER_URL) {
childWindow.loadURL(`${url}#${arg}`)
} else {
childWindow.loadFile(indexHtml, { hash: arg })
}
})
function domReady(condition: DocumentReadyState[] = ['complete', 'interactive']) {
return new Promise((resolve) => {
if (condition.includes(document.readyState)) {
resolve(true)
} else {
document.addEventListener('readystatechange', () => {
if (condition.includes(document.readyState)) {
resolve(true)
}
})
}
})
}
const safeDOM = {
append(parent: HTMLElement, child: HTMLElement) {
if (!Array.from(parent.children).find(e => e === child)) {
return parent.appendChild(child)
}
},
remove(parent: HTMLElement, child: HTMLElement) {
if (Array.from(parent.children).find(e => e === child)) {
return parent.removeChild(child)
}
},
}
/**
* https://tobiasahlin.com/spinkit
* https://connoratherton.com/loaders
* https://projects.lukehaas.me/css-loaders
* https://matejkustec.github.io/SpinThatShit
*/
function useLoading() {
const className = `loaders-css__square-spin`
const styleContent = `
@keyframes square-spin {
25% { transform: perspective(100px) rotateX(180deg) rotateY(0); }
50% { transform: perspective(100px) rotateX(180deg) rotateY(180deg); }
75% { transform: perspective(100px) rotateX(0) rotateY(180deg); }
100% { transform: perspective(100px) rotateX(0) rotateY(0); }
}
.${className} > div {
animation-fill-mode: both;
width: 50px;
height: 50px;
background: #fff;
animation: square-spin 3s 0s cubic-bezier(0.09, 0.57, 0.49, 0.9) infinite;
}
.app-loading-wrap {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background: #282c34;
z-index: 9;
}
`
const oStyle = document.createElement('style')
const oDiv = document.createElement('div')
oStyle.id = 'app-loading-style'
oStyle.innerHTML = styleContent
oDiv.className = 'app-loading-wrap'
oDiv.innerHTML = `<div class="${className}"><div></div></div>`
return {
appendLoading() {
safeDOM.append(document.head, oStyle)
safeDOM.append(document.body, oDiv)
},
removeLoading() {
safeDOM.remove(document.head, oStyle)
safeDOM.remove(document.body, oDiv)
},
}
}
// ----------------------------------------------------------------------
const { appendLoading, removeLoading } = useLoading()
domReady().then(appendLoading)
window.onmessage = (ev) => {
ev.data.payload === 'removeLoading' && removeLoading()
}
setTimeout(removeLoading, 4999)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<link rel="icon" href="/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>射频通道</title>
</head>
<script>
window._CONFIG = {};
window._CONFIG['publicURL'] = 'http://192.168.3.130:10030';
window._CONFIG['wsURL'] = 'ws://192.168.3.130:10030/notice/'
</script>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
{
"name": "junmp-channel",
"version": "1.0.0",
"main": "dist-electron/main/index.js",
"description": "Really simple Electron + Vue + Vite boilerplate.",
"author": "草鞋没号 <308487730@qq.com>",
"license": "MIT",
"private": true,
"keywords": [
"electron",
"rollup",
"vite",
"vue3",
"vue"
],
"debug": {
"env": {
"VITE_DEV_SERVER_URL": "http://127.0.0.1:3344/"
}
},
"scripts": {
"dev": "vite",
"build": "vue-tsc --noEmit && vite build && electron-builder",
"preview": "vite preview"
},
"devDependencies": {
"@vitejs/plugin-vue": "^4.0.0",
"electron": "^22.0.0",
"electron-builder": "^23.6.0",
"typescript": "^4.9.4",
"vite": "^4.0.3",
"vite-plugin-electron": "^0.11.1",
"vite-plugin-electron-renderer": "^0.11.3",
"vue": "^3.2.45",
"vue-tsc": "^1.0.16",
"axios": "^1.2.1",
"element-plus": "^2.2.27",
"pinia": "^2.0.28",
"vue-router": "^4.1.6",
"@vue/test-utils": "^2.2.6",
"less": "^4.1.2",
"jsdom": "^20.0.3",
"vitest": "^0.25.6"
}
}
<svg xmlns="http://www.w3.org/2000/svg" width="216" height="216" viewBox="0 0 216 216"><path fill="#80bd01" d="M104.6 180.7c-2 0-3.9-.5-5.7-1.5l-18.1-10.7c-2.7-1.5-1.4-2-.5-2.4 3.6-1.2 4.3-1.5 8.2-3.7.4-.2.9-.1 1.3.1l13.9 8.2c.5.3 1.2.3 1.7 0l54.1-31.2c.5-.3.8-.9.8-1.5V75.7c0-.6-.3-1.2-.8-1.5l-54-31.2c-.5-.3-1.2-.3-1.7 0l-54 31.2c-.5.3-.9.9-.9 1.5v62.4c0 .6.3 1.2.9 1.4l14.8 8.6c8 4 13-.7 13-5.5V81c0-.9.7-1.6 1.6-1.6h6.9c.9 0 1.6.7 1.6 1.6v61.6c0 10.7-5.8 16.9-16 16.9-3.1 0-5.6 0-12.5-3.4L44.8 148c-3.5-2-5.7-5.8-5.7-9.9V75.7c0-4.1 2.2-7.8 5.7-9.9l54.1-31.2c3.4-1.9 8-1.9 11.4 0l54.1 31.2c3.5 2 5.7 5.8 5.7 9.9v62.4c0 4.1-2.2 7.8-5.7 9.9l-54.1 31.2c-1.8 1-3.7 1.5-5.7 1.5zm43.6-61.5c0-11.7-7.9-14.8-24.5-17-16.8-2.2-18.5-3.4-18.5-7.3 0-3.2 1.4-7.6 13.9-7.6 11.1 0 15.2 2.4 16.9 9.9.1.7.8 1.2 1.5 1.2h7c.4 0 .8-.2 1.1-.5.3-.3.5-.8.4-1.2-1.1-12.9-9.7-18.9-27-18.9-15.4 0-24.6 6.5-24.6 17.4 0 11.8 9.1 15.1 23.9 16.6 17.7 1.7 19.1 4.3 19.1 7.8 0 6-4.8 8.6-16.2 8.6-14.3 0-17.5-3.6-18.5-10.7-.1-.8-.8-1.3-1.6-1.3h-7c-.9 0-1.6.7-1.6 1.6 0 9.1 5 20 28.6 20 17.3-.1 27.1-6.8 27.1-18.6zM172 55.9V57h3v8h1.2v-8h3.1v-1.1H172zm8.4 9.1h1.2v-7.6l2.6 7.6h1.2l2.6-7.6V65h1.2v-9h-1.7l-2.6 7.6-2.6-7.6h-1.8v9z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
\ No newline at end of file
<script setup>
import { ElConfigProvider } from 'element-plus'
import { RouterView } from 'vue-router'
import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
</script>
<template>
<el-config-provider :locale="zhCn">
<RouterView />
</el-config-provider>
</template>
import { axios } from '@/utils/request'
//post
export function postAction(url,parameter) {
return axios({
url: url,
method:'post',
data: parameter
})
}
//put
export function putAction(url,parameter) {
return axios({
url: url,
method:'put',
data: parameter
})
}
//get
export function getAction(url,parameter) {
return axios({
url: url,
method: 'get',
params: parameter
})
}
//deleteAction
export function deleteAction(url,parameter) {
return axios({
url: url,
method: 'delete',
params: parameter
})
}
/**
* 下载文件 用于excel导出
* @param url
* @param parameter
* @returns {*}
*/
export function downFile(url,parameter){
return axios({
url: url,
params: parameter,
method:'get' ,
responseType: 'blob'
})
}
/**
* 下载文件
* @param url 文件路径
* @param fileName 文件名
* @param parameter
* @returns {*}
*/
export function downloadFile(url, fileName, parameter) {
return downFile(url, parameter).then((data) => {
if (!data || data.size === 0) {
Vue.prototype['$message'].warning('文件下载失败')
return
}
if (typeof window.navigator.msSaveBlob !== 'undefined') {
window.navigator.msSaveBlob(new Blob([data]), fileName)
} else {
let url = window.URL.createObjectURL(new Blob([data]))
let link = document.createElement('a')
link.style.display = 'none'
link.href = url
link.setAttribute('download', fileName)
document.body.appendChild(link)
link.click()
document.body.removeChild(link) //下载完成移除元素
window.URL.revokeObjectURL(url) //释放掉blob对象
}
})
}
/**
* 文件上传 用于富文本上传图片
* @param url
* @param parameter
* @returns {*}
*/
export function uploadAction(url,parameter){
return axios({
url: url,
data: parameter,
method:'post' ,
headers: {
'Content-Type': 'multipart/form-data', // 文件上传
},
})
}
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1672900357670" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="15295" width="16" height="16" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M672 64H416a32 32 0 0 0-32 32 96.11 96.11 0 0 1-96 96 32 32 0 0 0-32 32v128a32 32 0 0 0 32 32h96v544a32 32 0 0 0 32 32h256a32 32 0 0 0 32-32V96a32 32 0 0 0-32-32z m-227.21 64H640v96.08A159.19 159.19 0 0 0 544 192H415.91a159.33 159.33 0 0 0 28.88-64zM448 384h64v512h-64z m192 512h-64V368a48.05 48.05 0 0 0-48-48H320v-64h224a96.11 96.11 0 0 1 96 96z" fill="#1296db" p-id="15296"></path></svg>
\ No newline at end of file
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1672900465854" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="15738" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16"><path d="M896 352v-64A224 224 0 0 0 672 64H160a32 32 0 0 0-32 32v256a32 32 0 0 0 32 32h314.43L158.81 752.21a128.1 128.1 0 0 0-30.81 83.3V928a32 32 0 0 0 32 32h704a32 32 0 0 0 32-32V672a32 32 0 0 0-32-32H674.58L889 372a32 32 0 0 0 7-20zM672 128a160.15 160.15 0 0 1 140.5 83.5A159 159 0 0 0 736 192H192v-64zM192 896v-60.49a64 64 0 0 1 15.41-41.65L558.72 384h75.7L295.7 779.17A32 32 0 0 0 320 832h512v64z m640-128H389.58l55-64.18a32 32 0 0 0 3.42 0.18h384zM499.29 640l229-267.17A32 32 0 0 0 704 320H192v-64h544a96.13 96.13 0 0 1 95.42 85.5L592.62 640z" fill="#1296db" p-id="15739"></path></svg>
\ No newline at end of file
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1672900475044" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="15941" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16"><path d="M830.39 129.61A222.53 222.53 0 0 0 672 64H160a32 32 0 0 0-32 32v256a32 32 0 0 0 32 32h352a32.05 32.05 0 0 1 30 20.78l-84.38 84.38-0.09 0.09-0.13 0.12a32 32 0 0 0-6 36.94l28.6 57.24V608a32 32 0 0 1-32 32H160a32 32 0 0 0-32 32v256a32 32 0 0 0 32 32h448a288 288 0 0 0 288-288 32 32 0 0 0-7-20L781.61 517.79 883.2 441.6A32 32 0 0 0 896 416V288a222.53 222.53 0 0 0-65.61-158.39zM672 128c73.16 0 135 49.35 154 116.51A207.12 207.12 0 0 0 688 192H192v-64zM448 704a96.17 96.17 0 0 0 91.38-66.56l36 45.07A96.14 96.14 0 0 1 480 768H192v-64zM192 896v-64h288c88.22 0 160-71.78 160-160a32 32 0 0 0-7-20L522.88 514.37l75.75-75.74A32 32 0 0 0 608 416a95.56 95.56 0 0 0-5.49-32H672a32 32 0 0 1 28.92 18.31L588.8 486.4c-0.27 0.2-0.54 0.39-0.8 0.6a32 32 0 0 0-5 45l121 151.23V688c0 114.69-93.31 208-208 208z m495-14.41c0.43-0.42 0.87-0.83 1.29-1.26A270.19 270.19 0 0 0 768 688v-16a32 32 0 0 0-7-20L653.61 517.79 755.2 441.6A32 32 0 0 0 768 416a96.11 96.11 0 0 0-96-96H192v-64h496c79.4 0 144 64.6 144 144l-115.2 86.4a32 32 0 0 0-6.4 44.8c0.2 0.27 0.42 0.52 0.62 0.78L831.74 682.9c-4.38 90.98-63.31 167.89-144.74 198.69z" fill="#1296db" p-id="15942"></path></svg>
\ No newline at end of file
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1672900492812" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="16144" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16"><path d="M928 448h-96V96a32 32 0 0 0-32-32H590.14a127.36 127.36 0 0 0-99.95 48L156.05 529.71a128.46 128.46 0 0 0-28.05 80v127.63a31.92 31.92 0 0 0 11 22.79 32.09 32.09 0 0 0 9.53 5.75h0.22A31.89 31.89 0 0 0 160 768h352v160a32 32 0 0 0 32 32h256a32 32 0 0 0 32-32V768h96a32 32 0 0 0 32-32V480a32 32 0 0 0-32-32zM192 609.67a64.27 64.27 0 0 1 14-40L540.17 152a63.66 63.66 0 0 1 50-24H640v448h-64V256a32 32 0 0 0-57-20L192 644.78zM457 576l55-68.77V576z m119 320V768h64v128z m320-192h-64v-64h64z m0-128h-96a32 32 0 0 0-32 32v288h-64V736a32 32 0 0 0-32-32H226.58L512 347.23v57.54L365.41 588a32 32 0 0 0 25 52H672a32 32 0 0 0 32-32V128h64v352a32 32 0 0 0 32 32h96z" fill="#1296db" p-id="16145"></path></svg>
\ No newline at end of file
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1672902598104" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="16491" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16"><path d="M873.52 65.44A31.89 31.89 0 0 0 864 64H160a32 32 0 0 0-32 32v329.34a224 224 0 0 0 123.82 200.35L280.45 640H160a32 32 0 0 0-32 32v256a32 32 0 0 0 32 32h448a288 288 0 0 0 288-288v-73.34a224 224 0 0 0-123.82-200.35L743.55 384H864a32 32 0 0 0 32-32V96a32 32 0 0 0-22.48-30.56zM832 128v64H192v-64zM192 425.34V256h640v64H288a32 32 0 0 0-32 32v79.11a111.1 111.1 0 0 0 61.42 99.38L536.45 640h-112.9l-143.1-71.55A159.13 159.13 0 0 1 192 425.34z m220.62-7.25L678 550.76A47.11 47.11 0 0 1 656.89 640h-18.33a51.49 51.49 0 0 0-27.18-34.09L346 473.24a46.84 46.84 0 0 1-26-42.13V384h65.44a51.49 51.49 0 0 0 27.18 34.09zM608 896H192v-64h480a222.38 222.38 0 0 0 122.87-36.64C754.74 856 686 896 608 896z m224-297.34V608c0 88.22-71.78 160-160 160H192v-64h464.89a111.11 111.11 0 0 0 49.69-210.49L487.56 384h112.89l143.1 71.55A159.13 159.13 0 0 1 832 598.66z" fill="#1296db" p-id="16492"></path></svg>
\ No newline at end of file
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1672902609607" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="16694" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16"><path d="M811.65 340.35A286.15 286.15 0 0 0 608 256h-68.77L575 104v-0.08l0.14-0.59A32 32 0 0 0 544 64H288a32 32 0 0 0-31.15 24.67l-128 544A32.27 32.27 0 0 0 128 640v32a288 288 0 0 0 288 288h192a288 288 0 0 0 288-288V544a286.15 286.15 0 0 0-84.35-203.65zM313.34 128h62.26L256.85 632.67A32.27 32.27 0 0 0 256 640v32a32 32 0 0 0 32 32h256a95.73 95.73 0 0 0 27.87-4.13A96.17 96.17 0 0 1 480 768H288a96.11 96.11 0 0 1-96-96v-28.29zM544 576a32 32 0 0 1 0 64h-95.17l15.09-64zM416 896a223.29 223.29 0 0 1-159.77-67.17A160.64 160.64 0 0 0 288 832h192c88.22 0 160-71.78 160-160v-64a95.73 95.73 0 0 0-4.13-27.87A96.17 96.17 0 0 1 704 672c0 123.51-100.49 224-224 224z m256-9.32q6-5.34 11.67-11A286.15 286.15 0 0 0 768 672c0-88.22-71.78-160-160-160H438.59a32 32 0 0 0-31.15 24.66L383.07 640h-62.2l120.47-512h62.26l-66 280.67A32 32 0 0 0 468.71 448H608c123.51 0 224 100.49 224 224 0 101.29-67.58 187.08-160 214.68z m139.65-418.33A286.15 286.15 0 0 0 608 384h-98.89l15.06-64H608c101.29 0 187.08 67.58 214.68 160q-5.34-5.93-11.03-11.65z" fill="#1296db" p-id="16695"></path></svg>
\ No newline at end of file
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1672902614980" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="16897" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16"><path d="M864 64H160a32 32 0 0 0-32 32v256a32 32 0 0 0 32 32h317.11a1121.38 1121.38 0 0 0-209.28 476.07l-11.31 62.21A32 32 0 0 0 288 960h256a32 32 0 0 0 31.24-25.06l2.76-12.29a1058.45 1058.45 0 0 1 241.56-472.49l44.11-49.62a127.88 127.88 0 0 0 32.33-85V96a32 32 0 0 0-32-32z m-32 64v64H192v-64zM330.79 871.52A1057.21 1057.21 0 0 1 558.84 384h74.89a1121.64 1121.64 0 0 0-242 502.35l-1.96 9.65h-63.43zM832 315.5a63.92 63.92 0 0 1-16.17 42.5l-44.11 49.62A1122.78 1122.78 0 0 0 518.41 896h-63.36a1057.65 1057.65 0 0 1 240.17-485.38l32.86-37.55A32 32 0 0 0 704 320H192v-64h640z" fill="#1296db" p-id="16898"></path></svg>
\ No newline at end of file
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1672902624722" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="17100" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16"><path d="M830.39 129.61A222.53 222.53 0 0 0 672 64H416a288 288 0 0 0-288 288 32 32 0 0 0 2.29 11.88L188 508.26l-54.67 82A32 32 0 0 0 128 608v128a224 224 0 0 0 224 224h320a224 224 0 0 0 224-224 31.92 31.92 0 0 0-1.64-10.12l-59.81-179.42 58.07-116.15A32 32 0 0 0 896 416V288a222.53 222.53 0 0 0-65.61-158.39zM672 128c73.16 0 135 49.35 154 116.51A207.12 207.12 0 0 0 688 192H544c-88.22 0-160 71.78-160 160a32 32 0 0 0 2.29 11.88L445.94 513l-28.3 84.88A31.92 31.92 0 0 0 416 608a95.56 95.56 0 0 0 5.49 32H352a32.06 32.06 0 0 1-31-23.88l57.39-86.07c0-0.06 0.07-0.12 0.11-0.17l0.09-0.13a31.92 31.92 0 0 0 3.09-29.63L320 345.84V336c0-114.69 93.31-208 208-208zM544 384a32.07 32.07 0 0 1 31.36 25.69l-60 120a31.93 31.93 0 0 0-1.74 24.43l24.24 72.7A32.07 32.07 0 0 1 512 640a32.05 32.05 0 0 1-31.71-27.68l30.06-90.19a31.81 31.81 0 0 0 0-20.25l-30.07-90.2A32.05 32.05 0 0 1 512 384zM337 142.42l-1.28 1.25A270.19 270.19 0 0 0 256 336v16a32 32 0 0 0 2.29 11.88L316 508.26l-54.67 82A32 32 0 0 0 256 608a96.11 96.11 0 0 0 96 96h160a95.77 95.77 0 0 0 47.41-12.57l16.3 48.89A32.05 32.05 0 0 1 544 768H336c-79.4 0-144-64.6-144-144v-6.31l58.43-87.64c0-0.06 0.07-0.12 0.11-0.17l0.09-0.13a31.92 31.92 0 0 0 3.09-29.63L192.08 346c2.45-93.09 62.01-172.22 144.92-203.58zM352 896c-73.16 0-135-49.35-154-116.51A207.12 207.12 0 0 0 336 832h208a96.11 96.11 0 0 0 96-96 31.92 31.92 0 0 0-1.64-10.12l-59.81-179.42 58.07-116.15A32 32 0 0 0 640 416a95.56 95.56 0 0 0-5.49-32H672a32.06 32.06 0 0 1 31.38 25.69l-60 120a31.93 31.93 0 0 0-1.74 24.43L704 741.19V752c0 79.4-64.6 144-144 144z m363.49-6A207.14 207.14 0 0 0 768 752v-16a31.92 31.92 0 0 0-1.64-10.12l-59.81-179.42 58.07-116.15A32 32 0 0 0 768 416a96.11 96.11 0 0 0-96-96H512a95.64 95.64 0 0 0-63.69 24.23A96.14 96.14 0 0 1 544 256h144c79.4 0 144 64.6 144 144v8.45l-60.62 121.24a31.86 31.86 0 0 0-1.73 24.45L831.92 741c-2.17 70.94-50.79 130.43-116.43 149z" fill="#1296db" p-id="17101"></path></svg>
\ No newline at end of file
/* color palette from <https://github.com/vuejs/theme> */
:root {
--vt-c-white: #ffffff;
--vt-c-white-soft: #f8f8f8;
--vt-c-white-mute: #f2f2f2;
--vt-c-black: #181818;
--vt-c-black-soft: #222222;
--vt-c-black-mute: #282828;
--vt-c-indigo: #2c3e50;
--vt-c-divider-light-1: rgba(60, 60, 60, 0.29);
--vt-c-divider-light-2: rgba(60, 60, 60, 0.12);
--vt-c-divider-dark-1: rgba(84, 84, 84, 0.65);
--vt-c-divider-dark-2: rgba(84, 84, 84, 0.48);
--vt-c-text-light-1: var(--vt-c-indigo);
--vt-c-text-light-2: rgba(60, 60, 60, 0.66);
--vt-c-text-dark-1: var(--vt-c-white);
--vt-c-text-dark-2: rgba(235, 235, 235, 0.64);
}
/* semantic color variables for this project */
:root {
--color-background: var(--vt-c-white);
--color-background-soft: var(--vt-c-white-soft);
--color-background-mute: var(--vt-c-white-mute);
--color-border: var(--vt-c-divider-light-2);
--color-border-hover: var(--vt-c-divider-light-1);
--color-heading: var(--vt-c-text-light-1);
--color-text: var(--vt-c-text-light-1);
--section-gap: 160px;
}
@media (prefers-color-scheme: dark) {
:root {
--color-background: var(--vt-c-black);
--color-background-soft: var(--vt-c-black-soft);
--color-background-mute: var(--vt-c-black-mute);
--color-border: var(--vt-c-divider-dark-2);
--color-border-hover: var(--vt-c-divider-dark-1);
--color-heading: var(--vt-c-text-dark-1);
--color-text: var(--vt-c-text-dark-2);
}
}
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
position: relative;
font-weight: normal;
}
body {
min-height: 100vh;
color: var(--color-text);
background: var(--color-background);
transition: color 0.5s, background-color 0.5s;
line-height: 1.6;
font-family: Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu,
Cantarell, 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
font-size: 15px;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
/* Logo 字体 */
@font-face {
font-family: "iconfont logo";
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834');
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix') format('embedded-opentype'),
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'),
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'),
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont') format('svg');
}
.logo {
font-family: "iconfont logo";
font-size: 160px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
/* tabs */
.nav-tabs {
position: relative;
}
.nav-tabs .nav-more {
position: absolute;
right: 0;
bottom: 0;
height: 42px;
line-height: 42px;
color: #666;
}
#tabs {
border-bottom: 1px solid #eee;
}
#tabs li {
cursor: pointer;
width: 100px;
height: 40px;
line-height: 40px;
text-align: center;
font-size: 16px;
border-bottom: 2px solid transparent;
position: relative;
z-index: 1;
margin-bottom: -1px;
color: #666;
}
#tabs .active {
border-bottom-color: #f00;
color: #222;
}
.tab-container .content {
display: none;
}
/* 页面布局 */
.main {
padding: 30px 100px;
width: 960px;
margin: 0 auto;
}
.main .logo {
color: #333;
text-align: left;
margin-bottom: 30px;
line-height: 1;
height: 110px;
margin-top: -50px;
overflow: hidden;
*zoom: 1;
}
.main .logo a {
font-size: 160px;
color: #333;
}
.helps {
margin-top: 40px;
}
.helps pre {
padding: 20px;
margin: 10px 0;
border: solid 1px #e7e1cd;
background-color: #fffdef;
overflow: auto;
}
.icon_lists {
width: 100% !important;
overflow: hidden;
*zoom: 1;
}
.icon_lists li {
width: 100px;
margin-bottom: 10px;
margin-right: 20px;
text-align: center;
list-style: none !important;
cursor: default;
}
.icon_lists li .code-name {
line-height: 1.2;
}
.icon_lists .icon {
display: block;
height: 100px;
line-height: 100px;
font-size: 42px;
margin: 10px auto;
color: #333;
-webkit-transition: font-size 0.25s linear, width 0.25s linear;
-moz-transition: font-size 0.25s linear, width 0.25s linear;
transition: font-size 0.25s linear, width 0.25s linear;
}
.icon_lists .icon:hover {
font-size: 100px;
}
.icon_lists .svg-icon {
/* 通过设置 font-size 来改变图标大小 */
width: 1em;
/* 图标和文字相邻时,垂直对齐 */
vertical-align: -0.15em;
/* 通过设置 color 来改变 SVG 的颜色/fill */
fill: currentColor;
/* path 和 stroke 溢出 viewBox 部分在 IE 下会显示
normalize.css 中也包含这行 */
overflow: hidden;
}
.icon_lists li .name,
.icon_lists li .code-name {
color: #666;
}
/* markdown 样式 */
.markdown {
color: #666;
font-size: 14px;
line-height: 1.8;
}
.highlight {
line-height: 1.5;
}
.markdown img {
vertical-align: middle;
max-width: 100%;
}
.markdown h1 {
color: #404040;
font-weight: 500;
line-height: 40px;
margin-bottom: 24px;
}
.markdown h2,
.markdown h3,
.markdown h4,
.markdown h5,
.markdown h6 {
color: #404040;
margin: 1.6em 0 0.6em 0;
font-weight: 500;
clear: both;
}
.markdown h1 {
font-size: 28px;
}
.markdown h2 {
font-size: 22px;
}
.markdown h3 {
font-size: 16px;
}
.markdown h4 {
font-size: 14px;
}
.markdown h5 {
font-size: 12px;
}
.markdown h6 {
font-size: 12px;
}
.markdown hr {
height: 1px;
border: 0;
background: #e9e9e9;
margin: 16px 0;
clear: both;
}
.markdown p {
margin: 1em 0;
}
.markdown>p,
.markdown>blockquote,
.markdown>.highlight,
.markdown>ol,
.markdown>ul {
width: 80%;
}
.markdown ul>li {
list-style: circle;
}
.markdown>ul li,
.markdown blockquote ul>li {
margin-left: 20px;
padding-left: 4px;
}
.markdown>ul li p,
.markdown>ol li p {
margin: 0.6em 0;
}
.markdown ol>li {
list-style: decimal;
}
.markdown>ol li,
.markdown blockquote ol>li {
margin-left: 20px;
padding-left: 4px;
}
.markdown code {
margin: 0 3px;
padding: 0 5px;
background: #eee;
border-radius: 3px;
}
.markdown strong,
.markdown b {
font-weight: 600;
}
.markdown>table {
border-collapse: collapse;
border-spacing: 0px;
empty-cells: show;
border: 1px solid #e9e9e9;
width: 95%;
margin-bottom: 24px;
}
.markdown>table th {
white-space: nowrap;
color: #333;
font-weight: 600;
}
.markdown>table th,
.markdown>table td {
border: 1px solid #e9e9e9;
padding: 8px 16px;
text-align: left;
}
.markdown>table th {
background: #F7F7F7;
}
.markdown blockquote {
font-size: 90%;
color: #999;
border-left: 4px solid #e9e9e9;
padding-left: 0.8em;
margin: 1em 0;
}
.markdown blockquote p {
margin: 0;
}
.markdown .anchor {
opacity: 0;
transition: opacity 0.3s ease;
margin-left: 8px;
}
.markdown .waiting {
color: #ccc;
}
.markdown h1:hover .anchor,
.markdown h2:hover .anchor,
.markdown h3:hover .anchor,
.markdown h4:hover .anchor,
.markdown h5:hover .anchor,
.markdown h6:hover .anchor {
opacity: 1;
display: inline-block;
}
.markdown>br,
.markdown>p>br {
clear: both;
}
.hljs {
display: block;
background: white;
padding: 0.5em;
color: #333333;
overflow-x: auto;
}
.hljs-comment,
.hljs-meta {
color: #969896;
}
.hljs-string,
.hljs-variable,
.hljs-template-variable,
.hljs-strong,
.hljs-emphasis,
.hljs-quote {
color: #df5000;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-type {
color: #a71d5d;
}
.hljs-literal,
.hljs-symbol,
.hljs-bullet,
.hljs-attribute {
color: #0086b3;
}
.hljs-section,
.hljs-name {
color: #63a35c;
}
.hljs-tag {
color: #333333;
}
.hljs-title,
.hljs-attr,
.hljs-selector-id,
.hljs-selector-class,
.hljs-selector-attr,
.hljs-selector-pseudo {
color: #795da3;
}
.hljs-addition {
color: #55a532;
background-color: #eaffea;
}
.hljs-deletion {
color: #bd2c00;
background-color: #ffecec;
}
.hljs-link {
text-decoration: underline;
}
/* 代码高亮 */
/* PrismJS 1.15.0
https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */
/**
* prism.js default theme for JavaScript, CSS and HTML
* Based on dabblet (http://dabblet.com)
* @author Lea Verou
*/
code[class*="language-"],
pre[class*="language-"] {
color: black;
background: none;
text-shadow: 0 1px white;
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
line-height: 1.5;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
pre[class*="language-"]::-moz-selection,
pre[class*="language-"] ::-moz-selection,
code[class*="language-"]::-moz-selection,
code[class*="language-"] ::-moz-selection {
text-shadow: none;
background: #b3d4fc;
}
pre[class*="language-"]::selection,
pre[class*="language-"] ::selection,
code[class*="language-"]::selection,
code[class*="language-"] ::selection {
text-shadow: none;
background: #b3d4fc;
}
@media print {
code[class*="language-"],
pre[class*="language-"] {
text-shadow: none;
}
}
/* Code blocks */
pre[class*="language-"] {
padding: 1em;
margin: .5em 0;
overflow: auto;
}
:not(pre)>code[class*="language-"],
pre[class*="language-"] {
background: #f5f2f0;
}
/* Inline code */
:not(pre)>code[class*="language-"] {
padding: .1em;
border-radius: .3em;
white-space: normal;
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: slategray;
}
.token.punctuation {
color: #999;
}
.namespace {
opacity: .7;
}
.token.property,
.token.tag,
.token.boolean,
.token.number,
.token.constant,
.token.symbol,
.token.deleted {
color: #905;
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
color: #690;
}
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string {
color: #9a6e3a;
background: hsla(0, 0%, 100%, .5);
}
.token.atrule,
.token.attr-value,
.token.keyword {
color: #07a;
}
.token.function,
.token.class-name {
color: #DD4A68;
}
.token.regex,
.token.important,
.token.variable {
color: #e90;
}
.token.important,
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>iconfont Demo</title>
<link rel="shortcut icon" href="//img.alicdn.com/imgextra/i4/O1CN01Z5paLz1O0zuCC7osS_!!6000000001644-55-tps-83-82.svg" type="image/x-icon"/>
<link rel="icon" type="image/svg+xml" href="//img.alicdn.com/imgextra/i4/O1CN01Z5paLz1O0zuCC7osS_!!6000000001644-55-tps-83-82.svg"/>
<link rel="stylesheet" href="https://g.alicdn.com/thx/cube/1.3.2/cube.min.css">
<link rel="stylesheet" href="demo.css">
<link rel="stylesheet" href="iconfont.css">
<script src="iconfont.js"></script>
<!-- jQuery -->
<script src="https://a1.alicdn.com/oss/uploads/2018/12/26/7bfddb60-08e8-11e9-9b04-53e73bb6408b.js"></script>
<!-- 代码高亮 -->
<script src="https://a1.alicdn.com/oss/uploads/2018/12/26/a3f714d0-08e6-11e9-8a15-ebf944d7534c.js"></script>
<style>
.main .logo {
margin-top: 0;
height: auto;
}
.main .logo a {
display: flex;
align-items: center;
}
.main .logo .sub-title {
margin-left: 0.5em;
font-size: 22px;
color: #fff;
background: linear-gradient(-45deg, #3967FF, #B500FE);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
</style>
</head>
<body>
<div class="main">
<h1 class="logo"><a href="https://www.iconfont.cn/" title="iconfont 首页" target="_blank">
<img width="200" src="https://img.alicdn.com/imgextra/i3/O1CN01Mn65HV1FfSEzR6DKv_!!6000000000514-55-tps-228-59.svg">
</a></h1>
<div class="nav-tabs">
<ul id="tabs" class="dib-box">
<li class="dib active"><span>Unicode</span></li>
<li class="dib"><span>Font class</span></li>
<li class="dib"><span>Symbol</span></li>
</ul>
<a href="https://www.iconfont.cn/manage/index?manage_type=myprojects&projectId=3834385" target="_blank" class="nav-more">查看项目</a>
</div>
<div class="tab-container">
<div class="content unicode" style="display: block;">
<ul class="icon_lists dib-box">
<li class="dib">
<span class="icon iconfont">&#xe74f;</span>
<div class="name">查询</div>
<div class="code-name">&amp;#xe74f;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe630;</span>
<div class="name">出库管理</div>
<div class="code-name">&amp;#xe630;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe634;</span>
<div class="name">入库管理</div>
<div class="code-name">&amp;#xe634;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe617;</span>
<div class="name">设置</div>
<div class="code-name">&amp;#xe617;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe637;</span>
<div class="name">调制识别</div>
<div class="code-name">&amp;#xe637;</div>
</li>
</ul>
<div class="article markdown">
<h2 id="unicode-">Unicode 引用</h2>
<hr>
<p>Unicode 是字体在网页端最原始的应用方式,特点是:</p>
<ul>
<li>支持按字体的方式去动态调整图标大小,颜色等等。</li>
<li>默认情况下不支持多色,直接添加多色图标会自动去色。</li>
</ul>
<blockquote>
<p>注意:新版 iconfont 支持两种方式引用多色图标:SVG symbol 引用方式和彩色字体图标模式。(使用彩色字体图标需要在「编辑项目」中开启「彩色」选项后并重新生成。)</p>
</blockquote>
<p>Unicode 使用步骤如下:</p>
<h3 id="-font-face">第一步:拷贝项目下面生成的 <code>@font-face</code></h3>
<pre><code class="language-css"
>@font-face {
font-family: 'iconfont';
src: url('iconfont.woff2?t=1671590477257') format('woff2'),
url('iconfont.woff?t=1671590477257') format('woff'),
url('iconfont.ttf?t=1671590477257') format('truetype');
}
</code></pre>
<h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
<pre><code class="language-css"
>.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
</code></pre>
<h3 id="-">第三步:挑选相应图标并获取字体编码,应用于页面</h3>
<pre>
<code class="language-html"
>&lt;span class="iconfont"&gt;&amp;#x33;&lt;/span&gt;
</code></pre>
<blockquote>
<p>"iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。</p>
</blockquote>
</div>
</div>
<div class="content font-class">
<ul class="icon_lists dib-box">
<li class="dib">
<span class="icon iconfont icon-chaxun"></span>
<div class="name">
查询
</div>
<div class="code-name">.icon-chaxun
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-chukuguanli-"></span>
<div class="name">
出库管理
</div>
<div class="code-name">.icon-chukuguanli-
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-rukuguanli-"></span>
<div class="name">
入库管理
</div>
<div class="code-name">.icon-rukuguanli-
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-shezhi"></span>
<div class="name">
设置
</div>
<div class="code-name">.icon-shezhi
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-tiaozhishibie"></span>
<div class="name">
调制识别
</div>
<div class="code-name">.icon-tiaozhishibie
</div>
</li>
</ul>
<div class="article markdown">
<h2 id="font-class-">font-class 引用</h2>
<hr>
<p>font-class 是 Unicode 使用方式的一种变种,主要是解决 Unicode 书写不直观,语意不明确的问题。</p>
<p>与 Unicode 使用方式相比,具有如下特点:</p>
<ul>
<li>相比于 Unicode 语意明确,书写更直观。可以很容易分辨这个 icon 是什么。</li>
<li>因为使用 class 来定义图标,所以当要替换图标时,只需要修改 class 里面的 Unicode 引用。</li>
</ul>
<p>使用步骤如下:</p>
<h3 id="-fontclass-">第一步:引入项目下面生成的 fontclass 代码:</h3>
<pre><code class="language-html">&lt;link rel="stylesheet" href="./iconfont.css"&gt;
</code></pre>
<h3 id="-">第二步:挑选相应图标并获取类名,应用于页面:</h3>
<pre><code class="language-html">&lt;span class="iconfont icon-xxx"&gt;&lt;/span&gt;
</code></pre>
<blockquote>
<p>"
iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。</p>
</blockquote>
</div>
</div>
<div class="content symbol">
<ul class="icon_lists dib-box">
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-chaxun"></use>
</svg>
<div class="name">查询</div>
<div class="code-name">#icon-chaxun</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-chukuguanli-"></use>
</svg>
<div class="name">出库管理</div>
<div class="code-name">#icon-chukuguanli-</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-rukuguanli-"></use>
</svg>
<div class="name">入库管理</div>
<div class="code-name">#icon-rukuguanli-</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-shezhi"></use>
</svg>
<div class="name">设置</div>
<div class="code-name">#icon-shezhi</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-tiaozhishibie"></use>
</svg>
<div class="name">调制识别</div>
<div class="code-name">#icon-tiaozhishibie</div>
</li>
</ul>
<div class="article markdown">
<h2 id="symbol-">Symbol 引用</h2>
<hr>
<p>这是一种全新的使用方式,应该说这才是未来的主流,也是平台目前推荐的用法。相关介绍可以参考这篇<a href="">文章</a>
这种用法其实是做了一个 SVG 的集合,与另外两种相比具有如下特点:</p>
<ul>
<li>支持多色图标了,不再受单色限制。</li>
<li>通过一些技巧,支持像字体那样,通过 <code>font-size</code>, <code>color</code> 来调整样式。</li>
<li>兼容性较差,支持 IE9+,及现代浏览器。</li>
<li>浏览器渲染 SVG 的性能一般,还不如 png。</li>
</ul>
<p>使用步骤如下:</p>
<h3 id="-symbol-">第一步:引入项目下面生成的 symbol 代码:</h3>
<pre><code class="language-html">&lt;script src="./iconfont.js"&gt;&lt;/script&gt;
</code></pre>
<h3 id="-css-">第二步:加入通用 CSS 代码(引入一次就行):</h3>
<pre><code class="language-html">&lt;style&gt;
.icon {
width: 1em;
height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
&lt;/style&gt;
</code></pre>
<h3 id="-">第三步:挑选相应图标并获取类名,应用于页面:</h3>
<pre><code class="language-html">&lt;svg class="icon" aria-hidden="true"&gt;
&lt;use xlink:href="#icon-xxx"&gt;&lt;/use&gt;
&lt;/svg&gt;
</code></pre>
</div>
</div>
</div>
</div>
<script>
$(document).ready(function () {
$('.tab-container .content:first').show()
$('#tabs li').click(function (e) {
var tabContent = $('.tab-container .content')
var index = $(this).index()
if ($(this).hasClass('active')) {
return
} else {
$('#tabs li').removeClass('active')
$(this).addClass('active')
tabContent.hide().eq(index).fadeIn()
}
})
})
</script>
</body>
</html>
@font-face {
font-family: "iconfont"; /* Project id 3834385 */
src: url('iconfont.woff2?t=1671590477257') format('woff2'),
url('iconfont.woff?t=1671590477257') format('woff'),
url('iconfont.ttf?t=1671590477257') format('truetype');
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-chaxun:before {
content: "\e74f";
}
.icon-chukuguanli-:before {
content: "\e630";
}
.icon-rukuguanli-:before {
content: "\e634";
}
.icon-shezhi:before {
content: "\e617";
}
.icon-tiaozhishibie:before {
content: "\e637";
}
window._iconfont_svg_string_3834385='<svg><symbol id="icon-chaxun" viewBox="0 0 1024 1024"><path d="M170.666667 910.222222V113.777778h682.666666v455.111111h56.888889V56.888889H113.777778v910.222222h398.222222v-56.888889z" fill="#333333" ></path><path d="M227.555556 568.888889h227.555555v56.888889H227.555556v-56.888889z m0-170.666667h568.888888v56.888889H227.555556V398.222222z m0-170.666666h341.333333v56.888888H227.555556V227.555556z" fill="#333333" ></path><path d="M682.666667 625.777778c62.577778 0 113.777778 51.2 113.777777 113.777778s-51.2 113.777778-113.777777 113.777777-113.777778-51.2-113.777778-113.777777 51.2-113.777778 113.777778-113.777778m0-56.888889c-96.711111 0-170.666667 73.955556-170.666667 170.666667s73.955556 170.666667 170.666667 170.666666 170.666667-73.955556 170.666666-170.666666-73.955556-170.666667-170.666666-170.666667z" fill="#333333" ></path><path d="M967.111111 967.111111l-164.977778-130.844444M794.737778 800.256l211.057778 164.067556-34.872889 44.942222-211.114667-164.067556z" fill="#333333" ></path></symbol><symbol id="icon-chukuguanli-" viewBox="0 0 1024 1024"><path d="M949.57 423.68L533.7 70.85a32 32 0 0 0-41.4 0L76.43 423.68a32 32 0 0 0 41.4 48.8l11.07-9.39v463.65a32 32 0 0 0 64 0V409.31v-0.5L513 137.22l320.16 271.63v198.24a32 32 0 0 0 64 0V463.14l11 9.34a32 32 0 1 0 41.4-48.8z" fill="#666666" ></path><path d="M256.85 862.49m12 0l72 0q12 0 12 12l0 72q0 12-12 12l-72 0q-12 0-12-12l0-72q0-12 12-12Z" fill="#666666" ></path><path d="M400.86 862.49m12 0l72 0q12 0 12 12l0 72q0 12-12 12l-72 0q-12 0-12-12l0-72q0-12 12-12Z" fill="#666666" ></path><path d="M257.58 735.38m12 0l72 0q12 0 12 12l0 72q0 12-12 12l-72 0q-12 0-12-12l0-72q0-12 12-12Z" fill="#666666" ></path><path d="M257.58 607.9m12 0l72 0q12 0 12 12l0 72q0 12-12 12l-72 0q-12 0-12-12l0-72q0-12 12-12Z" fill="#666666" ></path><path d="M400.86 734.65m12 0l72 0q12 0 12 12l0 72q0 12-12 12l-72 0q-12 0-12-12l0-72q0-12 12-12Z" fill="#666666" ></path><path d="M544.86 862.49m12 0l72 0q12 0 12 12l0 72q0 12-12 12l-72 0q-12 0-12-12l0-72q0-12 12-12Z" fill="#666666" ></path><path d="M896.14 782.1V781.47v-0.56V780.26c0-0.21-0.05-0.43-0.08-0.64s0-0.32-0.06-0.47V779c0-0.23-0.08-0.47-0.12-0.7s0-0.26-0.07-0.4v-0.1c0-0.24-0.1-0.47-0.16-0.71s-0.05-0.24-0.08-0.37v-0.12l-0.18-0.68-0.1-0.36v-0.14c-0.06-0.21-0.13-0.42-0.2-0.62l-0.13-0.39-0.06-0.17-0.21-0.55-0.16-0.42-0.08-0.19-0.21-0.47-0.2-0.46-0.1-0.21-0.19-0.39-0.23-0.47-0.12-0.21-0.17-0.3-0.06-0.11-0.25-0.45-0.13-0.21-0.15-0.24-0.11-0.18-0.53-0.38-0.13-0.18-0.14-0.21-0.16-0.23-0.28-0.4-0.11-0.15-0.16-0.2-0.2-0.26-0.3-0.39-0.09-0.11-0.21-0.24-0.21-0.25-0.32-0.37-0.33-0.35-0.29-0.3-0.24-0.25-64-63.69a25 25 0 1 0-35.26 35.45l21.07 21H679.12a25 25 0 0 0 0 50H810.7L789.43 829a25 25 0 0 0 35.31 35.4l64.07-63.92 0.24-0.25 0.55-0.58 0.06-0.07 0.36-0.41 0.38-0.44 0.09-0.11 0.33-0.42 0.18-0.2 0.25-0.33 0.12-0.15 0.31-0.44 0.07-0.1 0.21-0.3 0.13-0.19 0.29-0.46v-0.07l0.2-0.31 0.13-0.21 0.27-0.48 0.2-0.36 0.12-0.22 0.23-0.46 0.21-0.42 0.1-0.21 0.19-0.43 0.21-0.49 0.08-0.19 0.15-0.4 0.21-0.57 0.06-0.17 0.12-0.37c0.07-0.21 0.14-0.42 0.21-0.64v-0.15l0.1-0.35c0.06-0.23 0.13-0.45 0.18-0.68v-0.13c0-0.12 0.05-0.24 0.08-0.36s0.11-0.47 0.15-0.71v-0.11c0-0.13 0-0.26 0.07-0.39s0.08-0.46 0.12-0.69v-0.1c0-0.16 0-0.31 0.06-0.47s0.06-0.42 0.08-0.63v-0.09-0.61V783.97v-0.62-0.55c0.24-0.29 0.23-0.5 0.23-0.7z" fill="#666666" ></path></symbol><symbol id="icon-rukuguanli-" viewBox="0 0 1024 1024"><path d="M947.57 425.68L531.7 72.85a32 32 0 0 0-41.4 0L74.43 425.68a32 32 0 0 0 41.4 48.8l11.07-9.39v463.65a32 32 0 0 0 64 0V411.31v-0.5L511 139.22l320.16 271.63V609.08a32 32 0 0 0 64 0V465.14l11 9.34a32 32 0 1 0 41.4-48.8z" fill="#666666" ></path><path d="M511.01 864.49m12 0l72 0q12 0 12 12l0 72q0 12-12 12l-72 0q-12 0-12-12l0-72q0-12 12-12Z" fill="#666666" ></path><path d="M655.02 864.49m12 0l72 0q12 0 12 12l0 72q0 12-12 12l-72 0q-12 0-12-12l0-72q0-12 12-12Z" fill="#666666" ></path><path d="M511.75 737.38m12 0l72 0q12 0 12 12l0 72q0 12-12 12l-72 0q-12 0-12-12l0-72q0-12 12-12Z" fill="#666666" ></path><path d="M511.75 609.9m12 0l72 0q12 0 12 12l0 72q0 12-12 12l-72 0q-12 0-12-12l0-72q0-12 12-12Z" fill="#666666" ></path><path d="M655.02 736.65m12 0l72 0q12 0 12 12l0 72q0 12-12 12l-72 0q-12 0-12-12l0-72q0-12 12-12Z" fill="#666666" ></path><path d="M799.02 864.49m12 0l72 0q12 0 12 12l0 72q0 12-12 12l-72 0q-12 0-12-12l0-72q0-12 12-12Z" fill="#666666" ></path><path d="M446.89 760H315.3l21.27-21.22a25 25 0 0 0-35.31-35.4l-64.07 63.92-0.24 0.25-0.55 0.58-0.06 0.07-0.36 0.41-0.38 0.44-0.09 0.11-0.33 0.42-0.07 0.09-0.25 0.33-0.12 0.15-0.31 0.44-0.07 0.1-0.21 0.3-0.13 0.19-0.29 0.46v0.07l-0.2 0.31-0.13 0.21-0.27 0.48-0.2 0.36-0.12 0.22-0.23 0.46-0.21 0.42-0.1 0.21-0.19 0.43-0.21 0.49-0.08 0.2-0.15 0.4-0.21 0.57-0.06 0.17-0.12 0.37c-0.07 0.21-0.14 0.42-0.21 0.64v0.15l-0.1 0.35c-0.06 0.23-0.13 0.45-0.18 0.68v0.13c0 0.12-0.05 0.24-0.08 0.36s-0.11 0.47-0.15 0.71v0.11c0 0.13 0 0.26-0.07 0.39s-0.08 0.46-0.12 0.69v0.1c0 0.16 0 0.31-0.06 0.47s-0.06 0.42-0.08 0.63v4.91c0 0.21 0.05 0.43 0.08 0.64s0 0.32 0.06 0.47v0.09c0 0.23 0.08 0.47 0.12 0.7s0 0.26 0.07 0.4v0.1c0 0.24 0.1 0.47 0.16 0.71s0.05 0.24 0.08 0.37v0.12l0.18 0.68 0.1 0.36v0.14c0.06 0.21 0.13 0.42 0.2 0.62l0.13 0.39 0.06 0.17 0.21 0.55 0.16 0.42 0.08 0.19 0.2 0.47 0.2 0.46 0.1 0.21 0.19 0.38 0.23 0.47 0.12 0.21 0.17 0.3 0.06 0.11 0.25 0.45 0.13 0.21 0.15 0.24 0.11 0.18 0.27 0.42 0.13 0.18 0.14 0.21 0.16 0.23 0.28 0.4 0.11 0.15 0.16 0.2 0.2 0.26 0.3 0.39 0.09 0.11 0.21 0.24 0.21 0.25 0.32 0.37 0.33 0.35 0.29 0.3 0.24 0.25 64 63.69a25 25 0 1 0 35.26-35.45l-21.07-21h131.46a25 25 0 0 0 0-50z" fill="#666666" ></path></symbol><symbol id="icon-shezhi" viewBox="0 0 1024 1024"><path d="M512 672A160 160 0 1 1 672 512 160 160 0 0 1 512 672z m0-256A96 96 0 1 0 608 512 96 96 0 0 0 512 416z" fill="#4D4D4D" ></path><path d="M512 992a470.4 470.4 0 0 1-99.2-10.24 33.28 33.28 0 0 1-22.4-17.92l-64-140.8-147.84 16a35.2 35.2 0 0 1-27.52-10.88 482.56 482.56 0 0 1-99.2-179.84 33.92 33.92 0 0 1 5.12-28.16L139.52 512 56.96 403.84a33.92 33.92 0 0 1-5.12-28.16 482.56 482.56 0 0 1 99.2-179.84 34.56 34.56 0 0 1 27.52-10.88l147.84 16 64-140.8a33.28 33.28 0 0 1 22.4-17.92 493.44 493.44 0 0 1 198.4 0 33.28 33.28 0 0 1 22.4 17.92l64 140.8 147.84-16a34.56 34.56 0 0 1 27.52 10.88 482.56 482.56 0 0 1 99.2 179.84 33.92 33.92 0 0 1-5.12 28.16L884.48 512l82.56 108.16a33.92 33.92 0 0 1 5.12 28.16 482.56 482.56 0 0 1-99.2 179.84 34.56 34.56 0 0 1-27.52 10.88l-147.84-16-64 140.8a33.28 33.28 0 0 1-22.4 17.92A470.4 470.4 0 0 1 512 992z m-70.4-69.76a433.28 433.28 0 0 0 140.8 0l64-146.56a32.64 32.64 0 0 1 32.64-18.56l153.6 16a398.08 398.08 0 0 0 70.4-128L819.2 531.2a30.72 30.72 0 0 1 0-38.4l86.4-113.92a398.08 398.08 0 0 0-70.4-128l-153.6 16a33.28 33.28 0 0 1-32.64-18.56l-64-146.56a433.28 433.28 0 0 0-140.8 0l-64 146.56a33.28 33.28 0 0 1-32.64 18.56L192 250.88a398.08 398.08 0 0 0-70.4 128L204.8 492.8a30.72 30.72 0 0 1 0 38.4l-86.4 113.92a398.08 398.08 0 0 0 70.4 128l153.6-16a33.28 33.28 0 0 1 32.64 18.56z" fill="#4D4D4D" ></path></symbol><symbol id="icon-tiaozhishibie" viewBox="0 0 1024 1024"><path d="M995.555556 0h-303.786667a28.444444 28.444444 0 0 0 0 56.888889H967.111111v330.524444a28.444444 28.444444 0 1 0 56.888889 0V28.444444a28.444444 28.444444 0 0 0-28.444444-28.444444zM332.8 0H28.444444a28.444444 28.444444 0 0 0-28.444444 28.444444v358.968889a28.444444 28.444444 0 0 0 56.888889 0V56.888889h275.911111a28.444444 28.444444 0 0 0 0-56.888889zM995.555556 608.142222a28.444444 28.444444 0 0 0-28.444445 28.444445V967.111111h-275.342222a28.444444 28.444444 0 0 0 0 56.888889h303.786667a28.444444 28.444444 0 0 0 28.444444-28.444444v-358.968889a28.444444 28.444444 0 0 0-28.444444-28.444445zM332.8 967.111111H56.888889v-330.524444a28.444444 28.444444 0 0 0-56.888889 0v358.968889a28.444444 28.444444 0 0 0 28.444444 28.444444h304.355556a28.444444 28.444444 0 1 0 0-56.888889zM291.84 690.062222V435.768889a28.444444 28.444444 0 0 0-56.888889 0v254.293333a28.444444 28.444444 0 0 0 56.888889 0zM512 254.293333a28.444444 28.444444 0 0 0-28.444444 28.444445V739.555556a28.444444 28.444444 0 1 0 56.888888 0V284.444444a28.444444 28.444444 0 0 0-28.444444-30.151111zM789.048889 791.893333V232.106667a28.444444 28.444444 0 0 0-56.888889 0v559.786666a28.444444 28.444444 0 0 0 56.888889 0z" ></path></symbol></svg>',function(a){var l=(l=document.getElementsByTagName("script"))[l.length-1],t=l.getAttribute("data-injectcss"),l=l.getAttribute("data-disable-injectsvg");if(!l){var e,i,n,o,h,c=function(l,t){t.parentNode.insertBefore(l,t)};if(t&&!a.__iconfont__svg__cssinject__){a.__iconfont__svg__cssinject__=!0;try{document.write("<style>.svgfont {display: inline-block;width: 1em;height: 1em;fill: currentColor;vertical-align: -0.1em;font-size:16px;}</style>")}catch(l){console&&console.log(l)}}e=function(){var l,t=document.createElement("div");t.innerHTML=a._iconfont_svg_string_3834385,(t=t.getElementsByTagName("svg")[0])&&(t.setAttribute("aria-hidden","true"),t.style.position="absolute",t.style.width=0,t.style.height=0,t.style.overflow="hidden",t=t,(l=document.body).firstChild?c(t,l.firstChild):l.appendChild(t))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(e,0):(i=function(){document.removeEventListener("DOMContentLoaded",i,!1),e()},document.addEventListener("DOMContentLoaded",i,!1)):document.attachEvent&&(n=e,o=a.document,h=!1,s(),o.onreadystatechange=function(){"complete"==o.readyState&&(o.onreadystatechange=null,d())})}function d(){h||(h=!0,n())}function s(){try{o.documentElement.doScroll("left")}catch(l){return void setTimeout(s,50)}d()}}(window);
\ No newline at end of file
{
"id": "3834385",
"name": "channel",
"font_family": "iconfont",
"css_prefix_text": "icon-",
"description": "",
"glyphs": [
{
"icon_id": "3378474",
"name": "查询",
"font_class": "chaxun",
"unicode": "e74f",
"unicode_decimal": 59215
},
{
"icon_id": "6789076",
"name": "出库管理",
"font_class": "chukuguanli-",
"unicode": "e630",
"unicode_decimal": 58928
},
{
"icon_id": "6789086",
"name": "入库管理",
"font_class": "rukuguanli-",
"unicode": "e634",
"unicode_decimal": 58932
},
{
"icon_id": "10352321",
"name": "设置",
"font_class": "shezhi",
"unicode": "e617",
"unicode_decimal": 58903
},
{
"icon_id": "26033216",
"name": "调制识别",
"font_class": "tiaozhishibie",
"unicode": "e637",
"unicode_decimal": 58935
}
]
}
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 261.76 226.69" xmlns:v="https://vecta.io/nano"><path d="M161.096.001l-30.225 52.351L100.647.001H-.005l130.877 226.688L261.749.001z" fill="#41b883"/><path d="M161.096.001l-30.225 52.351L100.647.001H52.346l78.526 136.01L209.398.001z" fill="#34495e"/></svg>
\ No newline at end of file
@import './base.css';
#app {
margin: 0 auto;
min-height: 100vh;
font-weight: normal;
}
<script setup>
defineProps({
msg: {
type: String,
required: true
}
})
</script>
<template>
<div class="greetings">
<h1 class="green">{{ msg }}</h1>
<h3>
You’ve successfully created a project with
<a href="https://vitejs.dev/" target="_blank" rel="noopener">Vite</a> +
<a href="https://vuejs.org/" target="_blank" rel="noopener">Vue 3</a>.
</h3>
</div>
</template>
<style scoped>
h1 {
font-weight: 500;
font-size: 2.6rem;
top: -10px;
}
h3 {
font-size: 1.2rem;
}
.greetings h1,
.greetings h3 {
text-align: center;
}
@media (min-width: 1024px) {
.greetings h1,
.greetings h3 {
text-align: left;
}
}
</style>
<script setup>
import WelcomeItem from './WelcomeItem.vue'
import DocumentationIcon from './icons/IconDocumentation.vue'
import ToolingIcon from './icons/IconTooling.vue'
import EcosystemIcon from './icons/IconEcosystem.vue'
import CommunityIcon from './icons/IconCommunity.vue'
import SupportIcon from './icons/IconSupport.vue'
</script>
<template>
<WelcomeItem>
<template #icon>
<DocumentationIcon />
</template>
<template #heading>Documentation</template>
Vue’s
<a href="https://vuejs.org/" target="_blank" rel="noopener">official documentation</a>
provides you with all information you need to get started.
</WelcomeItem>
<WelcomeItem>
<template #icon>
<ToolingIcon />
</template>
<template #heading>Tooling</template>
This project is served and bundled with
<a href="https://vitejs.dev/guide/features.html" target="_blank" rel="noopener">Vite</a>. The
recommended IDE setup is
<a href="https://code.visualstudio.com/" target="_blank" rel="noopener">VSCode</a> +
<a href="https://github.com/johnsoncodehk/volar" target="_blank" rel="noopener">Volar</a>. If
you need to test your components and web pages, check out
<a href="https://www.cypress.io/" target="_blank" rel="noopener">Cypress</a> and
<a href="https://on.cypress.io/component" target="_blank">Cypress Component Testing</a>.
<br />
More instructions are available in <code>README.md</code>.
</WelcomeItem>
<WelcomeItem>
<template #icon>
<EcosystemIcon />
</template>
<template #heading>Ecosystem</template>
Get official tools and libraries for your project:
<a href="https://pinia.vuejs.org/" target="_blank" rel="noopener">Pinia</a>,
<a href="https://router.vuejs.org/" target="_blank" rel="noopener">Vue Router</a>,
<a href="https://test-utils.vuejs.org/" target="_blank" rel="noopener">Vue Test Utils</a>, and
<a href="https://github.com/vuejs/devtools" target="_blank" rel="noopener">Vue Dev Tools</a>. If
you need more resources, we suggest paying
<a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">Awesome Vue</a>
a visit.
</WelcomeItem>
<WelcomeItem>
<template #icon>
<CommunityIcon />
</template>
<template #heading>Community</template>
Got stuck? Ask your question on
<a href="https://chat.vuejs.org" target="_blank" rel="noopener">Vue Land</a>, our official
Discord server, or
<a href="https://stackoverflow.com/questions/tagged/vue.js" target="_blank" rel="noopener"
>StackOverflow</a
>. You should also subscribe to
<a href="https://news.vuejs.org" target="_blank" rel="noopener">our mailing list</a> and follow
the official
<a href="https://twitter.com/vuejs" target="_blank" rel="noopener">@vuejs</a>
twitter account for latest news in the Vue world.
</WelcomeItem>
<WelcomeItem>
<template #icon>
<SupportIcon />
</template>
<template #heading>Support Vue</template>
As an independent project, Vue relies on community backing for its sustainability. You can help
us by
<a href="https://vuejs.org/sponsor/" target="_blank" rel="noopener">becoming a sponsor</a>.
</WelcomeItem>
</template>
<template>
<div class="item">
<i>
<slot name="icon"></slot>
</i>
<div class="details">
<h3>
<slot name="heading"></slot>
</h3>
<slot></slot>
</div>
</div>
</template>
<style scoped>
.item {
margin-top: 2rem;
display: flex;
}
.details {
flex: 1;
margin-left: 1rem;
}
i {
display: flex;
place-items: center;
place-content: center;
width: 32px;
height: 32px;
color: var(--color-text);
}
h3 {
font-size: 1.2rem;
font-weight: 500;
margin-bottom: 0.4rem;
color: var(--color-heading);
}
@media (min-width: 1024px) {
.item {
margin-top: 0;
padding: 0.4rem 0 1rem calc(var(--section-gap) / 2);
}
i {
top: calc(50% - 25px);
left: -26px;
position: absolute;
border: 1px solid var(--color-border);
background: var(--color-background);
border-radius: 8px;
width: 50px;
height: 50px;
}
.item:before {
content: ' ';
border-left: 1px solid var(--color-border);
position: absolute;
left: 0;
bottom: calc(50% + 25px);
height: calc(50% - 25px);
}
.item:after {
content: ' ';
border-left: 1px solid var(--color-border);
position: absolute;
left: 0;
top: calc(50% + 25px);
height: calc(50% - 25px);
}
.item:first-of-type:before {
display: none;
}
.item:last-of-type:after {
display: none;
}
}
</style>
import { describe, it, expect } from 'vitest'
import { mount } from '@vue/test-utils'
import HelloWorld from '../HelloWorld.vue'
describe('HelloWorld', () => {
it('renders properly', () => {
const wrapper = mount(HelloWorld, { props: { msg: 'Hello Vitest' } })
expect(wrapper.text()).toContain('Hello Vitest')
})
})
<template>
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor">
<path
d="M15 4a1 1 0 1 0 0 2V4zm0 11v-1a1 1 0 0 0-1 1h1zm0 4l-.707.707A1 1 0 0 0 16 19h-1zm-4-4l.707-.707A1 1 0 0 0 11 14v1zm-4.707-1.293a1 1 0 0 0-1.414 1.414l1.414-1.414zm-.707.707l-.707-.707.707.707zM9 11v-1a1 1 0 0 0-.707.293L9 11zm-4 0h1a1 1 0 0 0-1-1v1zm0 4H4a1 1 0 0 0 1.707.707L5 15zm10-9h2V4h-2v2zm2 0a1 1 0 0 1 1 1h2a3 3 0 0 0-3-3v2zm1 1v6h2V7h-2zm0 6a1 1 0 0 1-1 1v2a3 3 0 0 0 3-3h-2zm-1 1h-2v2h2v-2zm-3 1v4h2v-4h-2zm1.707 3.293l-4-4-1.414 1.414 4 4 1.414-1.414zM11 14H7v2h4v-2zm-4 0c-.276 0-.525-.111-.707-.293l-1.414 1.414C5.42 15.663 6.172 16 7 16v-2zm-.707 1.121l3.414-3.414-1.414-1.414-3.414 3.414 1.414 1.414zM9 12h4v-2H9v2zm4 0a3 3 0 0 0 3-3h-2a1 1 0 0 1-1 1v2zm3-3V3h-2v6h2zm0-6a3 3 0 0 0-3-3v2a1 1 0 0 1 1 1h2zm-3-3H3v2h10V0zM3 0a3 3 0 0 0-3 3h2a1 1 0 0 1 1-1V0zM0 3v6h2V3H0zm0 6a3 3 0 0 0 3 3v-2a1 1 0 0 1-1-1H0zm3 3h2v-2H3v2zm1-1v4h2v-4H4zm1.707 4.707l.586-.586-1.414-1.414-.586.586 1.414 1.414z"
/>
</svg>
</template>
<template>
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="17" fill="currentColor">
<path
d="M11 2.253a1 1 0 1 0-2 0h2zm-2 13a1 1 0 1 0 2 0H9zm.447-12.167a1 1 0 1 0 1.107-1.666L9.447 3.086zM1 2.253L.447 1.42A1 1 0 0 0 0 2.253h1zm0 13H0a1 1 0 0 0 1.553.833L1 15.253zm8.447.833a1 1 0 1 0 1.107-1.666l-1.107 1.666zm0-14.666a1 1 0 1 0 1.107 1.666L9.447 1.42zM19 2.253h1a1 1 0 0 0-.447-.833L19 2.253zm0 13l-.553.833A1 1 0 0 0 20 15.253h-1zm-9.553-.833a1 1 0 1 0 1.107 1.666L9.447 14.42zM9 2.253v13h2v-13H9zm1.553-.833C9.203.523 7.42 0 5.5 0v2c1.572 0 2.961.431 3.947 1.086l1.107-1.666zM5.5 0C3.58 0 1.797.523.447 1.42l1.107 1.666C2.539 2.431 3.928 2 5.5 2V0zM0 2.253v13h2v-13H0zm1.553 13.833C2.539 15.431 3.928 15 5.5 15v-2c-1.92 0-3.703.523-5.053 1.42l1.107 1.666zM5.5 15c1.572 0 2.961.431 3.947 1.086l1.107-1.666C9.203 13.523 7.42 13 5.5 13v2zm5.053-11.914C11.539 2.431 12.928 2 14.5 2V0c-1.92 0-3.703.523-5.053 1.42l1.107 1.666zM14.5 2c1.573 0 2.961.431 3.947 1.086l1.107-1.666C18.203.523 16.421 0 14.5 0v2zm3.5.253v13h2v-13h-2zm1.553 12.167C18.203 13.523 16.421 13 14.5 13v2c1.573 0 2.961.431 3.947 1.086l1.107-1.666zM14.5 13c-1.92 0-3.703.523-5.053 1.42l1.107 1.666C11.539 15.431 12.928 15 14.5 15v-2z"
/>
</svg>
</template>
<template>
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="20" fill="currentColor">
<path
d="M11.447 8.894a1 1 0 1 0-.894-1.789l.894 1.789zm-2.894-.789a1 1 0 1 0 .894 1.789l-.894-1.789zm0 1.789a1 1 0 1 0 .894-1.789l-.894 1.789zM7.447 7.106a1 1 0 1 0-.894 1.789l.894-1.789zM10 9a1 1 0 1 0-2 0h2zm-2 2.5a1 1 0 1 0 2 0H8zm9.447-5.606a1 1 0 1 0-.894-1.789l.894 1.789zm-2.894-.789a1 1 0 1 0 .894 1.789l-.894-1.789zm2 .789a1 1 0 1 0 .894-1.789l-.894 1.789zm-1.106-2.789a1 1 0 1 0-.894 1.789l.894-1.789zM18 5a1 1 0 1 0-2 0h2zm-2 2.5a1 1 0 1 0 2 0h-2zm-5.447-4.606a1 1 0 1 0 .894-1.789l-.894 1.789zM9 1l.447-.894a1 1 0 0 0-.894 0L9 1zm-2.447.106a1 1 0 1 0 .894 1.789l-.894-1.789zm-6 3a1 1 0 1 0 .894 1.789L.553 4.106zm2.894.789a1 1 0 1 0-.894-1.789l.894 1.789zm-2-.789a1 1 0 1 0-.894 1.789l.894-1.789zm1.106 2.789a1 1 0 1 0 .894-1.789l-.894 1.789zM2 5a1 1 0 1 0-2 0h2zM0 7.5a1 1 0 1 0 2 0H0zm8.553 12.394a1 1 0 1 0 .894-1.789l-.894 1.789zm-1.106-2.789a1 1 0 1 0-.894 1.789l.894-1.789zm1.106 1a1 1 0 1 0 .894 1.789l-.894-1.789zm2.894.789a1 1 0 1 0-.894-1.789l.894 1.789zM8 19a1 1 0 1 0 2 0H8zm2-2.5a1 1 0 1 0-2 0h2zm-7.447.394a1 1 0 1 0 .894-1.789l-.894 1.789zM1 15H0a1 1 0 0 0 .553.894L1 15zm1-2.5a1 1 0 1 0-2 0h2zm12.553 2.606a1 1 0 1 0 .894 1.789l-.894-1.789zM17 15l.447.894A1 1 0 0 0 18 15h-1zm1-2.5a1 1 0 1 0-2 0h2zm-7.447-5.394l-2 1 .894 1.789 2-1-.894-1.789zm-1.106 1l-2-1-.894 1.789 2 1 .894-1.789zM8 9v2.5h2V9H8zm8.553-4.894l-2 1 .894 1.789 2-1-.894-1.789zm.894 0l-2-1-.894 1.789 2 1 .894-1.789zM16 5v2.5h2V5h-2zm-4.553-3.894l-2-1-.894 1.789 2 1 .894-1.789zm-2.894-1l-2 1 .894 1.789 2-1L8.553.106zM1.447 5.894l2-1-.894-1.789-2 1 .894 1.789zm-.894 0l2 1 .894-1.789-2-1-.894 1.789zM0 5v2.5h2V5H0zm9.447 13.106l-2-1-.894 1.789 2 1 .894-1.789zm0 1.789l2-1-.894-1.789-2 1 .894 1.789zM10 19v-2.5H8V19h2zm-6.553-3.894l-2-1-.894 1.789 2 1 .894-1.789zM2 15v-2.5H0V15h2zm13.447 1.894l2-1-.894-1.789-2 1 .894 1.789zM18 15v-2.5h-2V15h2z"
/>
</svg>
</template>
<template>
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor">
<path
d="M10 3.22l-.61-.6a5.5 5.5 0 0 0-7.666.105 5.5 5.5 0 0 0-.114 7.665L10 18.78l8.39-8.4a5.5 5.5 0 0 0-.114-7.665 5.5 5.5 0 0 0-7.666-.105l-.61.61z"
/>
</svg>
</template>
<!-- This icon is from <https://github.com/Templarian/MaterialDesign>, distributed under Apache 2.0 (https://www.apache.org/licenses/LICENSE-2.0) license-->
<template>
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
aria-hidden="true"
role="img"
class="iconify iconify--mdi"
width="24"
height="24"
preserveAspectRatio="xMidYMid meet"
viewBox="0 0 24 24"
>
<path
d="M20 18v-4h-3v1h-2v-1H9v1H7v-1H4v4h16M6.33 8l-1.74 4H7v-1h2v1h6v-1h2v1h2.41l-1.74-4H6.33M9 5v1h6V5H9m12.84 7.61c.1.22.16.48.16.8V18c0 .53-.21 1-.6 1.41c-.4.4-.85.59-1.4.59H4c-.55 0-1-.19-1.4-.59C2.21 19 2 18.53 2 18v-4.59c0-.32.06-.58.16-.8L4.5 7.22C4.84 6.41 5.45 6 6.33 6H7V5c0-.55.18-1 .57-1.41C7.96 3.2 8.44 3 9 3h6c.56 0 1.04.2 1.43.59c.39.41.57.86.57 1.41v1h.67c.88 0 1.49.41 1.83 1.22l2.34 5.39z"
fill="currentColor"
></path>
</svg>
</template>
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
import router from './router'
import './assets/main.css'
import './assets/iconfont/iconfont.css'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
const app = createApp(App)
app.use(createPinia())
app.use(router)
app.use(ElementPlus).mount('#app')
import { createRouter, createWebHistory, createWebHashHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'
const router = createRouter({
history: createWebHashHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/',
name: 'home',
component: HomeView
},
]
})
export default router
import { ref, computed } from 'vue'
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', () => {
const count = ref(0)
const doubleCount = computed(() => count.value * 2)
function increment() {
count.value++
}
return { count, doubleCount, increment }
})
const VueAxios = {
vm: {},
// eslint-disable-next-line no-unused-vars
install(Vue, router = {}, instance) {
if (this.installed) {
return;
}
this.installed = true;
if (!instance) {
// eslint-disable-next-line no-console
console.error('You have to install axios');
return;
}
Vue.axios = instance;
Object.defineProperties(Vue.prototype, {
axios: {
get: function get() {
return instance;
}
},
$http: {
get: function get() {
return instance;
}
}
});
}
};
export {
VueAxios
}
\ No newline at end of file
export function debounce(func, wait, immediate) {
let timeout, args, context, timestamp, result;
const later = function() {
// 据上一次触发时间间隔
const last = +new Date() - timestamp;
// 上次被包装函数被调用时间间隔 last 小于设定时间间隔 wait
if (last < wait && last > 0) {
timeout = setTimeout(later, wait - last);
} else {
timeout = null;
// 如果设定为immediate===true,因为开始边界已经调用过了此处无需调用
if (!immediate) {
result = func.apply(context, args);
if (!timeout) context = args = null;
}
}
};
return function(...args) {
context = this;
timestamp = +new Date();
const callNow = immediate && !timeout;
// 如果延时不存在,重新设定延时
if (!timeout) timeout = setTimeout(later, wait);
if (callNow) {
result = func.apply(context, args);
context = args = null;
}
return result;
};
}
/**
* @param {date} time 需要转换的时间
* @param {String} fmt 需要转换的格式 如 yyyy-MM-dd、yyyy-MM-dd HH:mm:ss
*/
export function formatTime(time, fmt) {
if (!time) return ''
else {
const date = new Date(time)
const o = {
'M+': date.getMonth() + 1,
'd+': date.getDate(),
'H+': date.getHours(),
'm+': date.getMinutes(),
's+': date.getSeconds(),
'q+': Math.floor((date.getMonth() + 3) / 3),
'S': date.getMilliseconds()
}
if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length))
for (const k in o) {
if (new RegExp('(' + k + ')').test(fmt)) {
fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : ((
'00' + o[k]).substr(('' + o[k]).length)))
}
}
return fmt
}
}
import axios from 'axios'
import { VueAxios } from './axios'
let apiBaseUrl = window._CONFIG['publicURL']
// 创建 axios 实例
const request = axios.create({
// API 请求的默认前缀
baseURL: apiBaseUrl,
timeout: 3000 // 请求超时时间
})
axios.interceptors.request.use((request) => {
return request
})
request.interceptors.response.use((response) => {
return response.data
})
const installer = {
vm: {},
install (Vue) {
Vue.use(VueAxios, request)
}
}
export default request
export {
installer as VueAxios,
request as axios
}
<template>
<div>
<el-tabs type="card" style="height: calc(100vh - 126px)">
<el-tab-pane label="系统配置">
<el-card>
<el-form :model="sysForm" :inline="true">
<el-form-item label="仓库编号">
<el-input v-model="sysForm.storeCode" />
</el-form-item>
<el-form-item label="服务器">
<el-input v-model="sysForm.serverIp" />
</el-form-item>
<el-form-item label="端口">
<el-input v-model="sysForm.serverPort" />
</el-form-item>
<el-form-item label="是否切换">
<el-checkbox v-model="sysForm.isHide" />
</el-form-item>
<el-form-item>
<el-button type="success" @click="getConfig">刷新</el-button>
<el-button type="primary" @click="saveConfig">保存</el-button>
<el-button type="primary" @click="syncGoods">同步物资</el-button>
</el-form-item>
</el-form>
</el-card>
</el-tab-pane>
<el-tab-pane label="通道配置">
<el-card>
<div class="head-container">
<el-button class="filter-item" type="primary" style="float: right" @click="add">新增</el-button>
</div>
<el-table :data="channelList" border style="width: 100%;">
<el-table-column prop="stationId" label="通道号" align="center" width="100"/>
<el-table-column prop="readerIp" label="读写器" align="center">
<template #default="scope">
{{scope.row.readerIp + ':' + scope.row.readerPort }}
</template>
</el-table-column>
<el-table-column prop="gpioIp" label="GPIO" align="center">
<template #default="scope">
{{scope.row.gpioIp + ':' + scope.row.gpioPort }}
</template>
</el-table-column>
<el-table-column prop="ledIp" label="显示器" align="center">
<template #default="scope">
{{scope.row.ledIp + ':' + scope.row.ledPort }}
</template>
</el-table-column>
<el-table-column label="操作" width="200" align="center">
<template #default="scope">
<el-button type="primary" size="small" @click="edit(scope.row)">编辑</el-button>
<el-popconfirm title="你确定删除吗?" @confirm="removeDevice(scope.row)">
<template #reference>
<el-button type="danger" size="small">删除</el-button>
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
</el-card>
</el-tab-pane>
</el-tabs>
<el-dialog v-model="innerVisible" width="30%" :title="title">
<el-form label-position="right" size="large" label-width="90px" :model="formData">
<el-form-item label="通道号">
<el-input v-model="formData.stationId" />
</el-form-item>
<el-row>
<el-col :span="12">
<el-form-item label="读写器IP">
<el-input v-model="formData.readerIp"/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="读写器端口">
<el-input v-model="formData.readerPort"/>
</el-form-item>
</el-col>
</el-row>
<el-form-item label="读写器类型">
<el-select v-model="formData.readerType" style="width: 100%;">
<el-option :value="4" label="索利得四通道"></el-option>
<el-option :value="8" label="索利得八通道"></el-option>
</el-select>
</el-form-item>
<el-form-item label="天线功率">
<el-input v-model="formData.readerPower"/>
</el-form-item>
<el-row>
<el-col :span="12">
<el-form-item label="GPIO的IP">
<el-input v-model="formData.gpioIp"/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="GPIO端口">
<el-input v-model="formData.gpioPort"/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="显示屏IP">
<el-input v-model="formData.ledIp"/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="显示屏端口">
<el-input v-model="formData.ledPort"/>
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="innerVisible = false">关闭</el-button>
<el-button type="primary" @click="handleSubmit">提交</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script>
import { defineComponent, ref, getCurrentInstance, toRefs, reactive } from 'vue'
import { postAction, getAction } from '@/api/manage'
import { ElMessage } from 'element-plus'
export default defineComponent({
setup() {
const channelList = ref([])
const title = ref('')
const sysForm = ref({})
const formData = ref({})
const innerVisible = ref(false)
const state = reactive({
url: {
getConfig: '/config/getConfig',
getDevice: '/device/getDevice',
updateDevice: '/device/updateDevice',
removeDevice: '/device/removeDevice',
saveDevice: '/device/saveDevice',
updateConfig: '/config/updateConfig',
saveConfig: '/config/saveConfig',
syncGoods: '/platform/syncGoods'
},
});
const loadData = (arg) => {
getConfig()
getDevice()
}
function getDevice() {
postAction(state.url.getDevice, {storeCode: JSON.parse(sessionStorage.getItem('storeInfo')).storeCode}).then(res => {
if (res.code !== 99200) return ElMessage.error(res.message);
channelList.value = res.data
})
}
function getConfig() {
postAction(state.url.getConfig, {}).then(res => {
if (res.code !== 99200) return ElMessage.error(res.message);
sysForm.value = {
id: res.data[0].id,
storeCode: res.data[0].storeCode,
serverIp: res.data[0].serverIp,
serverPort: res.data[0].serverPort
}
})
}
function syncGoods() {
getAction(state.url.syncGoods).then(res => {
if (res.code !== 99200) return ElMessage.error(res.message);
ElMessage.success(res.message)
})
}
function saveConfig() {
let url = sysForm.value.id ? state.url.updateConfig : state.url.saveConfig
postAction(url, sysForm.value).then(res => {
if (res.code !== 99200) return ElMessage.error(res.message);
ElMessage.success(res.message)
sessionStorage.setItem('storeInfo', JSON.stringify(sysForm.value))
})
}
function edit(row) {
title.value = '编辑通道'
formData.value = JSON.parse(JSON.stringify(row))
innerVisible.value = true
}
function add() {
title.value = '新增通道'
innerVisible.value = true
}
function handleSubmit() {
let url = formData.value.id ? state.url.updateDevice : state.url.saveDevice
formData.value.storeCode = JSON.parse(sessionStorage.getItem('storeInfo')).storeCode
postAction(url, formData.value).then(res => {
if (res.code !== 99200) return ElMessage.error(res.message);
ElMessage.success(res.message)
formData.value = {}
innerVisible.value = false
getDevice()
})
}
function removeDevice(row) {
postAction(state.url.removeDevice, {stationId: row.stationId, id: row.id}).then(res => {
if (res.code !== 99200) return ElMessage.error(res.message);
ElMessage.success(res.message)
getDevice()
})
}
return {
...toRefs(state),
sysForm,
formData,
innerVisible,
title,
channelList,
getConfig,
saveConfig,
add,
edit,
handleSubmit,
removeDevice,
loadData,
getDevice,
syncGoods
}
},
})
</script>
\ No newline at end of file
<template>
<el-tabs :tab-position="tabPosition" type="card" :stretch="true" class="menu-tabs" @tab-change="tabChange">
<el-tab-pane v-for="item in tabList" :key="item.title">
<template #label>
<span class="custom-tabs-label">
<span :class="item.icon"></span>
<span>{{item.title}}</span>
</span>
</template>
<component :is="item.template" :ref="item.template" @refresh="handleRefresh" @logChange="handleLogChange"></component>
</el-tab-pane>
<el-card>{{log}}</el-card>
</el-tabs>
</template>
<script>
import { defineComponent, ref, getCurrentInstance } from 'vue'
import RFID from './RFID.vue'
import InTask from './InTask.vue'
import OutTask from './OutTask.vue'
import Query from './Query.vue'
import Setting from './Setting.vue'
import ChannelSetting from './ChannelSetting.vue'
export default defineComponent({
components: { RFID, InTask, OutTask, Query, Setting, ChannelSetting },
setup() {
const { proxy } = getCurrentInstance()
const tabPosition = ref('bottom')
const log = ref('')
const tabList = [
{title: '射频识别', icon: 'iconfont icon-tiaozhishibie', template: 'RFID'},
{title: '入库作业', icon: 'iconfont icon-rukuguanli-', template: 'InTask'},
{title: '出库作业', icon: 'iconfont icon-chukuguanli-', template: 'OutTask'},
{title: '手动设置', icon: 'iconfont icon-shezhi', template: 'Setting'},
{title: '查询', icon: 'iconfont icon-chaxun', template: 'Query'},
{title: '通道配置', icon: 'iconfont icon-shezhi', template: 'ChannelSetting'},
]
function tabChange(index) {
proxy.$refs[tabList[index].template][0].loadData()
}
function handleRefresh() {
proxy.$refs.InTask[0].loadData()
proxy.$refs.OutTask[0].loadData()
}
function handleLogChange(data) {
log.value = data
}
return {
tabPosition,
tabList,
log,
tabChange,
handleRefresh,
handleLogChange
}
},
})
</script>
<style scope>
.menu-tabs > .el-tabs__content {
height: calc(100vh - 71px);
}
.el-tabs {
--el-tabs-header-height: 60px !important;
}
.el-tabs--border-card>.el-tabs__content {
padding: 0px !important;
}
</style>
<template>
<el-row :gutter="20">
<el-col :span="16">
<el-card style="height: calc(50vh - 68px);">
<template #header>
<div class="card-header">
<span>计划任务</span>
<el-button class="button" type="primary" @click="syncInBill" :loading="loading">入库单接收</el-button>
</div>
</template>
<el-table :data="billList" ref="bill" border style="width: 100%;height: 28.5vh;" highlight-current-row @row-click="billClick">
<el-table-column type="index" label="序号" width="60" align="center"/>
<el-table-column prop="bizBillNo" label="单据号" align="center"/>
<el-table-column prop="billName" label="凭证号" align="center"/>
<el-table-column prop="swOrgName" label="收物单位" align="center"/>
<el-table-column prop="percentage" label="进度" align="center">
<template #default="scope">
{{scope.row.percentage}}%
</template>
</el-table-column>
<el-table-column prop="activeState" label="状态" align="center">
<template #default="scope">
<el-tag size="small" type="success" v-if="scope.row.activeState == 0">空闲</el-tag>
<el-tag size="small" type="warning" v-if="scope.row.activeState == 1">激活中</el-tag>
<el-tag size="small" v-if="scope.row.activeState == 2">待上报</el-tag>
<el-tag size="small" v-if="scope.row.activeState == 3">已上报</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="200" align="center">
<template #default="scope">
<el-button type="success" size="small" @click="activateBill(scope.row)" v-if="scope.row.activeState == 0" :disabled="lockState">激活</el-button>
<el-button type="warning" size="small" @click="deactivate(scope.row)" v-if="scope.row.activeState == 1">解除</el-button>
<el-button type="primary" size="small" :disabled="scope.row.activeState !== 2" @click="reportBill(scope.row)">上报</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination
style="left: 40%;margin-top: 6px;"
background
@current-change="handleCurrentChange"
:current-page="searchData.pageNo"
:page-size="searchData.pageSize"
layout="total, prev, pager, next"
:total="total"
/>
</el-card>
<el-card style="height: calc(50vh - 68px);margin-top: 10px;">
<template #header>
<span>物资列表</span>
</template>
<el-table :data="goodsList" ref="goods" border style="width: 100%;height: 28.5vh;" highlight-current-row @row-click="goodsClick">
<el-table-column type="index" label="序号" width="60" align="center"/>
<el-table-column prop="goodsCode" label="品名代码" align="center"/>
<el-table-column prop="goodsName" label="品名" align="center"/>
<el-table-column prop="planAmount" label="计划数量" align="center"/>
<el-table-column prop="realAmount" label="实际数量" align="center"/>
</el-table>
<el-pagination
style="left: 40%;margin-top: 6px;"
background
@current-change="handleCurrentChange"
:current-page="searchData1.pageNo"
:page-size="searchData1.pageSize"
layout="total, prev, pager, next"
:total="total1"
/>
</el-card>
</el-col>
<el-col :span="8">
<el-card style="height: calc(100vh - 126px)">
<template #header>
<span>号型列表</span>
</template>
<el-table :data="modelList" border style="width: 100%;height: 70vh;">
<el-table-column type="index" label="序号" width="60" align="center"/>
<el-table-column prop="modelName" label="号型名称" align="center" width="180"/>
<el-table-column prop="planAmount" label="计划数量" align="center"/>
<el-table-column prop="realAmount" label="实际数量" align="center"/>
<el-table-column prop="writeAmount" label="手动修改数量" align="center">
<template #default="scope">
<div class="editable-cell">
<div v-if="editable" class="editable-cell-input-wrapper">
<el-input-number ref='inputs' size="small" style="height: 30px" :value="writeAmount" @change="handleChange" @blur="check" :max="scope.row.planAmount - scope.row.realAmount"/>
</div>
<div v-else class="editable-cell-text-wrapper" @dblclick="edit(scope.row)">
<span>{{ scope.row.writeAmount }}</span>
</div>
</div>
</template>
</el-table-column>
</el-table>
<el-pagination
style="left: 36%;margin-top: 6px;"
background
@current-change="handleCurrentChange"
:current-page="searchData2.pageNo"
:page-size="searchData2.pageSize"
layout="total, prev, pager, next"
:total="total2"
/>
</el-card>
</el-col>
</el-row>
</template>
<script>
import { defineComponent, ref, reactive, toRefs, getCurrentInstance } from 'vue'
import { ElMessage } from 'element-plus'
import { postAction, getAction } from '@/api/manage'
export default defineComponent({
setup() {
const billList = ref([])
const goodsList = ref([])
const modelList = ref([])
const selectBill = ref({})
const selectGoods = ref({})
const editable = ref(false)
const loading = ref(false)
const lockState = ref(false)
const writeAmount = ref()
const itemForm = ref({})
const { proxy } = getCurrentInstance()
const searchData = ref({
pageNo: 1,
pageSize: 5
})
const searchData1 = ref({
pageNo: 1,
pageSize: 5
})
const searchData2 = ref({
pageNo: 1,
pageSize: 10
})
const total = ref(0)
const total1 = ref(0)
const total2 = ref(0)
const state = reactive({
url: {
getBillPage: '/bill/getBillPage',
getGoodsPage: '/bill/getGoodsPage',
getModelPage: '/bill/getModelPage',
updateItem: '/bill/updateItem',
reportBill: '/platform/reportInBill',
activateBill: '/bill/activateBill',
syncInBill: '/platform/syncInBill'
},
storeInfo: {},
storeCode: ''
});
function handleCurrentChange (val) {
searchData.value.pageNo = val
loadData()
}
function handleCurrentChange1 (val) {
searchData1.value.pageNo = val
loadGoods()
}
function handleCurrentChange2 (val) {
searchData2.value.pageNo = val
loadModel()
}
const loadData = (arg) => {
if (sessionStorage.getItem('storeInfo')) {
searchData.value.storeCode = JSON.parse(sessionStorage.getItem('storeInfo')).storeCode
searchData.value.type = 'IN'
postAction(state.url.getBillPage, searchData.value).then(res => {
if (res.code !== 99200) return ElMessage.error(res.message);
billList.value = res.data.records
total.value = res.data.totalRows - 0
goodsList.value = []
modelList.value = []
if (res.data.records.length > 0) {
// 保证在获取到的单据里面只有一条单据是激活中的
res.data.records.find(i => i.activeState == 1) ? lockState.value = true : lockState.value = false
if (arg) {
proxy.$refs.bill.setCurrentRow(billList.value.find(i => i.billNo == selectBill.value.billNo))
loadGoods(1)
} else {
proxy.$refs.bill.setCurrentRow(billList.value[0])
selectBill.value = res.data.records[0]
loadGoods()
}
}
})
}
}
function loadGoods(arg) {
searchData1.value.storeCode = searchData.value.storeCode
searchData1.value.bizBillNo = selectBill.value.bizBillNo
postAction(state.url.getGoodsPage, searchData1.value).then(res => {
if (res.code !== 99200) return ElMessage.error(res.message);
goodsList.value = res.data.records
total1.value = res.data.totalRows - 0
if (res.data.records.length > 0) {
if (arg) {
proxy.$refs.goods.setCurrentRow(goodsList.value.find(i => i.goodsCode == selectGoods.value.goodsCode))
} else {
proxy.$refs.goods.setCurrentRow(goodsList.value[0])
selectGoods.value = res.data.records[0]
}
loadModel()
}
})
}
function loadModel() {
searchData2.value.storeCode = searchData.value.storeCode
searchData2.value.bizBillNo = selectBill.value.bizBillNo
searchData2.value.goodsCode = selectGoods.value.goodsCode
postAction(state.url.getModelPage, searchData2.value).then(res => {
if (res.code !== 99200) return ElMessage.error(res.message);
modelList.value = res.data.records
total2.value = res.data.totalRows - 0
})
}
function billClick(row) {
selectBill.value = row
loadGoods()
}
function goodsClick(row) {
selectGoods.value = row
loadModel()
}
function edit(row) {
proxy.editable = true;
itemForm.value = row
proxy.$nextTick((x) => {
if (proxy.$refs.inputs) {
proxy.$refs.inputs.focus();
}
})
}
function handleChange(e) {
writeAmount.value = e
itemForm.value.writeAmount = e
}
// 手动修改数量
function check() {
proxy.editable = false;
itemForm.value.bizBillNo = selectBill.value.bizBillNo
itemForm.value.storeCode = searchData.value.storeCode
postAction(state.url.updateItem, itemForm.value).then(res => {
if (res.code !== 99200) return ElMessage.error(res.message);
ElMessage.success(res.message)
loadData(1)
})
}
// 上报单据
function reportBill(row) {
getAction(state.url.reportBill, {storeCode: searchData.value.storeCode, billNo: row.billNo}).then(res => {
if (res.code !== 99200) return ElMessage.error(res.message);
ElMessage.success(res.message)
loadData()
})
}
// 激活单据
function activateBill(row) {
row.activeState = 1
postAction(state.url.activateBill, row).then(res => {
if (res.code !== 99200) {
row.activeState = 0
return ElMessage.error(res.message);
}
ElMessage.success(res.message)
searchData.value.pageNo = 1
loadData(1)
})
}
// 解除激活
function deactivate(row) {
row.activeState = 0
postAction(state.url.activateBill, row).then(res => {
if (res.code !== 99200) {
row.activeState = 1
return ElMessage.error(res.message);
}
ElMessage.success(res.message)
searchData.value.pageNo = 1
loadData(1)
})
}
// 同步单据
function syncInBill() {
loading.value = true
getAction(state.url.syncInBill, {storeCode: searchData.value.storeCode}).then(res => {
if (res.code !== 99200) return ElMessage.error(res.message);
ElMessage.success(res.message)
loading.value = false
loadData()
})
}
// loadData()
return {
...toRefs(state),
billList,
goodsList,
modelList,
selectBill,
selectGoods,
searchData,
searchData1,
searchData2,
total,
total1,
total2,
editable,
writeAmount,
itemForm,
lockState,
handleCurrentChange,
handleCurrentChange1,
handleCurrentChange2,
billClick,
goodsClick,
handleChange,
edit,
check,
reportBill,
loadData,
syncInBill,
activateBill,
deactivate,
loading
}
},
})
</script>
<style scoped>
.editable-cell {
position: relative;
}
.editable-cell-text-wrapper {
padding: 4px 5px 5px 5px;
cursor: pointer;
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
}
</style>
\ No newline at end of file
<template>
<el-row :gutter="20">
<el-col :span="16">
<el-card style="height: calc(50vh - 68px);">
<template #header>
<div class="card-header">
<span>计划任务</span>
<el-button class="button" type="primary" @click="syncOutBill" :loading="loading">出库单接收</el-button>
</div>
</template>
<el-table :data="billList" ref="bill" border style="width: 100%;height: 28.5vh;" highlight-current-row @row-click="billClick">
<el-table-column type="index" label="序号" width="60" align="center"/>
<el-table-column prop="bizBillNo" label="单据号" align="center"/>
<el-table-column prop="billName" label="凭证号" align="center"/>
<el-table-column prop="swOrgName" label="收物单位" align="center"/>
<el-table-column prop="percentage" label="进度" align="center">
<template #default="scope">
{{scope.row.percentage}}%
</template>
</el-table-column>
<el-table-column prop="activeState" label="状态" align="center">
<template #default="scope">
<el-tag size="small" type="success" v-if="scope.row.activeState == 0">空闲</el-tag>
<el-tag size="small" type="warning" v-if="scope.row.activeState == 1">激活中</el-tag>
<el-tag size="small" v-if="scope.row.activeState == 2">待上报</el-tag>
<el-tag size="small" v-if="scope.row.activeState == 3">已上报</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="200" align="center">
<template #default="scope">
<el-button type="success" size="small" @click="activateBill(scope.row)" v-if="scope.row.activeState == 0" :disabled="lockState">激活</el-button>
<el-button type="warning" size="small" @click="deactivate(scope.row)" v-if="scope.row.activeState == 1">解除</el-button>
<el-button type="primary" size="small" :disabled="scope.row.activeState !== 2" @click="reportBill(scope.row)">上报</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination
style="left: 40%;margin-top: 6px;"
background
@current-change="handleCurrentChange"
:current-page="searchData.pageNo"
:page-size="searchData.pageSize"
layout="total, prev, pager, next"
:total="total"
/>
</el-card>
<el-card style="height: calc(50vh - 68px);margin-top: 10px;">
<template #header>
<span>物资列表</span>
</template>
<el-table :data="goodsList" ref="goods" border style="width: 100%;height: 28.5vh;" highlight-current-row @row-click="goodsClick">
<el-table-column type="index" label="序号" width="60" align="center"/>
<el-table-column prop="goodsCode" label="品名代码" align="center"/>
<el-table-column prop="goodsName" label="品名" align="center"/>
<el-table-column prop="planAmount" label="计划数量" align="center"/>
<el-table-column prop="realAmount" label="实际数量" align="center"/>
</el-table>
<el-pagination
style="left: 40%;margin-top: 6px;"
background
@current-change="handleCurrentChange"
:current-page="searchData1.pageNo"
:page-size="searchData1.pageSize"
layout="total, prev, pager, next"
:total="total1"
/>
</el-card>
</el-col>
<el-col :span="8">
<el-card style="height: calc(100vh - 126px)">
<template #header>
<span>号型列表</span>
</template>
<el-table :data="modelList" border style="width: 100%;height: 70vh;">
<el-table-column type="index" label="序号" width="60" align="center"/>
<el-table-column prop="modelName" label="号型名称" align="center" width="180"/>
<el-table-column prop="planAmount" label="计划数量" align="center"/>
<el-table-column prop="realAmount" label="实际数量" align="center"/>
<el-table-column prop="writeAmount" label="手动修改数量" align="center">
<template #default="scope">
<div class="editable-cell">
<div v-if="editable" class="editable-cell-input-wrapper">
<el-input-number ref='inputs' size="small" style="height: 30px" :value="writeAmount" @change="handleChange" @blur="check" :max="scope.row.planAmount - scope.row.realAmount"/>
</div>
<div v-else class="editable-cell-text-wrapper" @dblclick="edit(scope.row)">
<span>{{ scope.row.writeAmount }}</span>
</div>
</div>
</template>
</el-table-column>
</el-table>
<el-pagination
style="left: 36%;margin-top: 6px;"
background
@current-change="handleCurrentChange"
:current-page="searchData2.pageNo"
:page-size="searchData2.pageSize"
layout="total, prev, pager, next"
:total="total2"
/>
</el-card>
</el-col>
</el-row>
</template>
<script>
import { defineComponent, ref, reactive, toRefs, getCurrentInstance } from 'vue'
import { ElMessage } from 'element-plus'
import { postAction, getAction } from '@/api/manage'
export default defineComponent({
setup() {
const billList = ref([])
const goodsList = ref([])
const modelList = ref([])
const selectBill = ref({})
const selectGoods = ref({})
const editable = ref(false)
const loading = ref(false)
const lockState = ref(false)
const writeAmount = ref()
const itemForm = ref({})
const { proxy } = getCurrentInstance()
const searchData = ref({
pageNo: 1,
pageSize: 5
})
const searchData1 = ref({
pageNo: 1,
pageSize: 5
})
const searchData2 = ref({
pageNo: 1,
pageSize: 10
})
const total = ref(0)
const total1 = ref(0)
const total2 = ref(0)
const state = reactive({
url: {
getBillPage: '/bill/getBillPage',
getGoodsPage: '/bill/getGoodsPage',
getModelPage: '/bill/getModelPage',
updateItem: '/bill/updateItem',
reportBill: '/platform/reportOutBill',
activateBill: '/bill/activateBill',
syncOutBill: '/platform/syncOutBill'
},
storeInfo: {},
storeCode: ''
});
function handleCurrentChange (val) {
searchData.value.pageNo = val
loadData()
}
function handleCurrentChange1 (val) {
searchData1.value.pageNo = val
loadGoods()
}
function handleCurrentChange2 (val) {
searchData2.value.pageNo = val
loadModel()
}
const loadData = (arg) => {
if (sessionStorage.getItem('storeInfo')) {
searchData.value.storeCode = JSON.parse(sessionStorage.getItem('storeInfo')).storeCode
searchData.value.type = 'OUT'
postAction(state.url.getBillPage, searchData.value).then(res => {
if (res.code !== 99200) return ElMessage.error(res.message);
billList.value = res.data.records
total.value = res.data.totalRows - 0
goodsList.value = []
modelList.value = []
if (res.data.records.length > 0) {
// 保证在获取到的单据里面只有一条单据是激活中的
res.data.records.find(i => i.activeState == 1) ? lockState.value = true : lockState.value = false
if (arg) {
proxy.$refs.bill.setCurrentRow(billList.value.find(i => i.billNo == selectBill.value.billNo))
loadGoods(1)
} else {
proxy.$refs.bill.setCurrentRow(billList.value[0])
selectBill.value = res.data.records[0]
loadGoods()
}
}
})
}
}
function loadGoods(arg) {
searchData1.value.storeCode = searchData.value.storeCode
searchData1.value.bizBillNo = selectBill.value.bizBillNo
postAction(state.url.getGoodsPage, searchData1.value).then(res => {
if (res.code !== 99200) return ElMessage.error(res.message);
goodsList.value = res.data.records
total1.value = res.data.totalRows - 0
if (res.data.records.length > 0) {
if (arg) {
proxy.$refs.goods.setCurrentRow(goodsList.value.find(i => i.goodsCode == selectGoods.value.goodsCode))
} else {
proxy.$refs.goods.setCurrentRow(goodsList.value[0])
selectGoods.value = res.data.records[0]
}
loadModel()
}
})
}
function loadModel() {
searchData2.value.storeCode = searchData.value.storeCode
searchData2.value.bizBillNo = selectBill.value.bizBillNo
searchData2.value.goodsCode = selectGoods.value.goodsCode
postAction(state.url.getModelPage, searchData2.value).then(res => {
if (res.code !== 99200) return ElMessage.error(res.message);
modelList.value = res.data.records
total2.value = res.data.totalRows - 0
})
}
function billClick(row) {
selectBill.value = row
loadGoods()
}
function goodsClick(row) {
selectGoods.value = row
loadModel()
}
function edit(row) {
proxy.editable = true;
itemForm.value = row
proxy.$nextTick((x) => {
if (proxy.$refs.inputs) {
proxy.$refs.inputs.focus();
}
})
}
function handleChange(e) {
writeAmount.value = e
itemForm.value.writeAmount = e
}
// 手动修改数量
function check() {
proxy.editable = false;
itemForm.value.bizBillNo = selectBill.value.bizBillNo
itemForm.value.storeCode = searchData.value.storeCode
postAction(state.url.updateItem, itemForm.value).then(res => {
if (res.code !== 99200) return ElMessage.error(res.message);
ElMessage.success(res.message)
loadData(1)
})
}
// 上报单据
function reportBill(row) {
getAction(state.url.reportBill, {storeCode: searchData.value.storeCode, billNo: row.billNo}).then(res => {
if (res.code !== 99200) return ElMessage.error(res.message);
ElMessage.success(res.message)
loadData()
})
}
// 激活单据
function activateBill(row) {
row.activeState = 1
postAction(state.url.activateBill, row).then(res => {
if (res.code !== 99200) {
row.activeState = 0
return ElMessage.error(res.message);
}
ElMessage.success(res.message)
searchData.value.pageNo = 1
loadData(1)
})
}
// 解除激活
function deactivate(row) {
row.activeState = 0
postAction(state.url.activateBill, row).then(res => {
if (res.code !== 99200) {
row.activeState = 1
return ElMessage.error(res.message);
}
ElMessage.success(res.message)
searchData.value.pageNo = 1
loadData(1)
})
}
// 同步单据
function syncOutBill() {
loading.value = true
getAction(state.url.syncOutBill, {storeCode: searchData.value.storeCode}).then(res => {
if (res.code !== 99200) return ElMessage.error(res.message);
ElMessage.success(res.message)
loading.value = false
loadData()
})
}
// loadData()
return {
...toRefs(state),
billList,
goodsList,
modelList,
selectBill,
selectGoods,
searchData,
searchData1,
searchData2,
total,
total1,
total2,
editable,
writeAmount,
itemForm,
lockState,
handleCurrentChange,
handleCurrentChange1,
handleCurrentChange2,
billClick,
goodsClick,
handleChange,
edit,
check,
reportBill,
loadData,
syncOutBill,
activateBill,
deactivate,
loading
}
},
})
</script>
<style scoped>
.editable-cell {
position: relative;
}
.editable-cell-text-wrapper {
padding: 4px 5px 5px 5px;
cursor: pointer;
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
}
</style>
\ No newline at end of file
<template>
<el-row :gutter="20">
<el-col :span="6">
<el-card>
<el-form label-position="right" size="large" label-width="100px" :model="formData" style="max-width: 460px;height: calc(100vh - 168px);">
<el-form-item label="开始时间">
<el-date-picker v-model="searchData.startTime" type="datetime" format="YYYY-MM-DD HH:mm:ss" value-format="YYYY-MM-DD HH:mm:ss" style="width: 100%;"/>
</el-form-item>
<el-form-item label="结束时间">
<el-date-picker v-model="searchData.endTime" type="datetime" format="YYYY-MM-DD HH:mm:ss" value-format="YYYY-MM-DD HH:mm:ss" style="width: 100%;"/>
</el-form-item>
<el-form-item label="出入库">
<el-select v-model="searchData.type" placeholder="请选择出入库" style="width: 100%;">
<el-option value="IN" label="入库"></el-option>
<el-option value="OUT" label="出库"></el-option>
</el-select>
</el-form-item>
<el-form-item label="品名">
<el-input v-model="searchData.goodsName" placeholder="请输入品名"/>
</el-form-item>
<el-form-item label="号型">
<el-input v-model="searchData.modelName" placeholder="请输入号型"/>
</el-form-item>
<el-button type="primary" style="width: 100%" @click="loadData">查询</el-button>
</el-form>
</el-card>
</el-col>
<el-col :span="18">
<el-card style="height: calc(100vh - 126px);">
<el-table :data="logList" border size="large" style="width: 100%;height: 78vh;">
<el-table-column type="index" label="序号" width="70" align="center"/>
<el-table-column prop="inState" label="出入库" align="center">
<template #default="scope">
{{ scope.row.type == 'IN' ? '入库' : '出库' }}
</template>
</el-table-column>
<el-table-column prop="billName" label="单号" align="center"/>
<el-table-column prop="goodsName" label="品名" align="center"/>
<el-table-column prop="modelName" label="号型" align="center"/>
<el-table-column prop="amount" label="数量" align="center"/>
<el-table-column prop="createTime" label="出入库日期" align="center"/>
</el-table>
<el-pagination
style="left: 40%;margin-top: 6px;"
background
@current-change="handleCurrentChange"
:current-page="searchData.pageNo"
:page-size="searchData.pageSize"
layout="total, prev, pager, next"
:total="total"
/>
</el-card>
</el-col>
</el-row>
</template>
<script>
import { defineComponent, ref, reactive, toRefs, getCurrentInstance } from 'vue'
import { ElMessage } from 'element-plus'
import { postAction } from '@/api/manage'
export default defineComponent({
setup() {
const logList = ref([])
const formData = ref({})
const { proxy } = getCurrentInstance()
const searchData = ref({
pageNo: 1,
pageSize: 10,
type: 'IN',
startTime: parseTime(new Date(new Date().setHours(0, 0, 0, 0))),
endTime: parseTime(new Date())
})
const total = ref(0)
function parseTime(time) {
if (time) {
var date = new Date(time)
var year = date.getFullYear()
/* 在日期格式中,月份是从0开始的,因此要加0
* 使用三元表达式在小于10的前面加0,以达到格式统一 如 09:11:05
* */
var month = date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1
var day = date.getDate() < 10 ? '0' + date.getDate() : date.getDate()
var hours = date.getHours() < 10 ? '0' + date.getHours() : date.getHours()
var minutes = date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes()
var seconds = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds()
// 拼接
return year + '-' + month + '-' + day + ' ' + hours + ':' + minutes + ':' + seconds
} else {
return ''
}
}
const state = reactive({
url: {
getGoodsRecord: '/log/getLogPage'
}
});
function handleCurrentChange (val) {
searchData.value.pageNo = val
loadData()
}
const loadData = () => {
if (sessionStorage.getItem('storeInfo')) {
let config = JSON.parse(sessionStorage.getItem('storeInfo'))
searchData.value.storeCode = config.storeCode
postAction(state.url.getGoodsRecord, searchData.value).then(res => {
if (res.code !== 99200) return ElMessage.error(res.message);
logList.value = res.data.records
total.value = res.data.totalRows - 0
})
}
}
// loadData()
return {
...toRefs(state),
logList,
formData,
searchData,
total,
loadData,
handleCurrentChange
}
},
})
</script>
\ No newline at end of file
<template>
<div>
<el-tabs type="border-card" v-model="activeTab">
<el-tab-pane v-for="item in channelList" :key="item" :label="'通道' + item.stationId" :name="item.stationId">
<el-card style="height: calc(100vh - 187px)">
<template #header>
<div class="card-header">
<span>实时出入库数据</span>
<el-button style="float: right;" type="primary" @click="showChannelSetting">通道配置</el-button>
</div>
</template>
<el-row :gutter="20">
<el-col :span="18">
<el-table :data="item.logData" size="large" border style="width: 100%;" max-height="720">
<el-table-column type="index" label="序号" width="70" align="center"/>
<el-table-column prop="stationType" label="作业类型" align="center">
<template #default="scope">
{{ scope.row.stationType == 'IN' ? '入库' : '出库' }}
</template>
</el-table-column>
<el-table-column prop="goodsCode" label="代码" align="center"/>
<el-table-column prop="goodsName" label="品名" align="center"/>
<el-table-column prop="modelName" label="号型" align="center"/>
<el-table-column prop="amount" label="箱内数量" align="center"/>
<el-table-column prop="xhNo" label="箱号" align="center"/>
</el-table>
</el-col>
<el-col :span="6">
<el-card class="box-card">
<template #header>
<div style="text-align: center;">
<span>识别总箱数</span>
</div>
</template>
<div class="text">{{ item.logData.length }}箱</div>
</el-card>
<el-divider />
<el-card class="box-card">
<template #header>
<div style="text-align: center;">
<span>异常次数</span>
</div>
</template>
<div class="text">{{ item.errNum }}次</div>
</el-card>
</el-col>
</el-row>
</el-card>
</el-tab-pane>
</el-tabs>
<el-dialog v-model="visible" width="45%">
<template #header>
<div style="text-align: center;font-size: 18px;font-family: Microsoft YaHei;font-weight: bold;color: #303133;">{{title}}</div>
</template>
<el-form size="large" :model="formData">
<el-collapse v-model="activeNames">
<el-collapse-item name="1">
<template #title>
<p class="title">&nbsp;读写器配置</p>
</template>
<el-card style="margin: 25px 35px 0 35px;">
<el-row :gutter="40">
<el-col :span="12">
<el-form-item>
<el-input v-model="formData.readerIp" placeholder="请输入读写器的IP">
<template #prefix>
<el-icon class="el-input__icon" style="color: #1296db"><Monitor /></el-icon>
</template>
</el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item>
<el-input v-model="formData.readerPort" placeholder="请输入读写器的端口">
<template #prefix>
<el-icon class="el-input__icon" style="color: #1296db"><Help /></el-icon>
</template>
</el-input>
</el-form-item>
</el-col>
</el-row>
</el-card>
</el-collapse-item>
<el-collapse-item name="2">
<template #title>
<p class="title">&nbsp;天线功率</p>
</template>
<el-card style="margin: 25px 35px 0 35px;">
<el-row :gutter="40">
<el-col :span="12">
<el-form-item>
<el-input v-model="power1" placeholder="请输入1号天线功率">
<template #prefix>
<img src="../assets/1.svg" width="16" height="16"/>
</template>
</el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item>
<el-input v-model="power2" placeholder="请输入2号天线功率">
<template #prefix>
<img src="../assets/2.svg" width="16" height="16"/>
</template>
</el-input>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="40" style="margin-top: 15px;">
<el-col :span="12">
<el-form-item>
<el-input v-model="power3" placeholder="请输入3号天线功率">
<template #prefix>
<img src="../assets/3.svg" width="16" height="16"/>
</template>
</el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item>
<el-input v-model="power4" placeholder="请输入4号天线功率">
<template #prefix>
<img src="../assets/4.svg" width="16" height="16"/>
</template>
</el-input>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="40" v-if="readerType == 8" style="margin-top: 15px;">
<el-col :span="12">
<el-form-item>
<el-input v-model="power5" placeholder="请输入5号天线功率">
<template #prefix>
<img src="../assets/5.svg" width="16" height="16"/>
</template>
</el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item>
<el-input v-model="power6" placeholder="请输入6号天线功率">
<template #prefix>
<img src="../assets/6.svg" width="16" height="16"/>
</template>
</el-input>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="40" v-if="readerType == 8" style="margin-top: 15px;">
<el-col :span="12">
<el-form-item>
<el-input v-model="power7" placeholder="请输入7号天线功率">
<template #prefix>
<img src="../assets/7.svg" width="16" height="16"/>
</template>
</el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item>
<el-input v-model="power8" placeholder="请输入8号天线功率">
<template #prefix>
<img src="../assets/8.svg" width="16" height="16"/>
</template>
</el-input>
</el-form-item>
</el-col>
</el-row>
</el-card>
</el-collapse-item>
<el-collapse-item name="3">
<template #title>
<p class="title">&nbsp;GPIO配置</p>
</template>
<el-card style="margin: 25px 35px 0 35px;">
<el-row :gutter="40">
<el-col :span="12">
<el-form-item>
<el-input v-model="formData.gpioIp" placeholder="请输入GPIO的IP">
<template #prefix>
<el-icon class="el-input__icon" style="color: #1296db"><Monitor /></el-icon>
</template>
</el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item>
<el-input v-model="formData.gpioPort" placeholder="请输入GPIO的端口">
<template #prefix>
<el-icon class="el-input__icon" style="color: #1296db"><Help /></el-icon>
</template>
</el-input>
</el-form-item>
</el-col>
</el-row>
</el-card>
</el-collapse-item>
</el-collapse>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="visible = false">关闭</el-button>
<el-button type="primary" @click="handleSubmit">提交</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script>
import { defineComponent, ref, reactive, toRefs } from 'vue'
import { ElMessage } from 'element-plus'
import { postAction, getAction } from '@/api/manage'
import { Help, Monitor } from '@element-plus/icons-vue'
export default defineComponent({
components: { Monitor, Help },
setup(props, {emit}) {
const channelList = ref([]);
const sysForm = ref({})
const logData = ref([])
const visible = ref(false)
const formData = ref({})
const activeTab = ref(1)
const activeNames = ref(['1','2','3'])
const readerType = ref(4)
const title = ref()
const power1 = ref()
const power2 = ref()
const power3 = ref()
const power4 = ref()
const power5 = ref()
const power6 = ref()
const power7 = ref()
const power8 = ref()
const log = ref('')
const state = reactive({
url: {
getConfig: '/config/getConfig',
getDevice: '/device/getDevice',
openReader: '/rfid/openReader',
updateDevice: '/device/updateDevice',
removeDevice: '/device/removeDevice',
saveDevice: '/device/saveDevice',
updateConfig: '/config/updateConfig'
},
storeInfo: {},
storeCode: '',
lockReconnect: false
});
// websocket开始
let websock = null
function initWebSocket () {
websock = new WebSocket(window._CONFIG['wsURL'] + JSON.parse(sessionStorage.getItem('storeInfo')).storeCode);
websock.onopen = websocketOnopen;
websock.onerror = websocketOnerror;
websock.onmessage = websocketOnmessage;
websock.onclose = websocketClose;
}
// Websoket连接成功事件
const websocketOnopen = (res) => {
console.log("WebSocket连接成功");
};
const map = new Map()
// Websoket接收消息事件
const websocketOnmessage = (res) => {
let message = JSON.parse(res.data)
logData.value = ''
if (message.noticeType == 0) {
map.set(message.stationId, '【通道' + message.stationId + ': ' + message.noticeInfo+"】\n")
for(let value of map.values()) {
logData.value += value
}
emit('logChange', logData.value)
}
if (message.noticeType == 2) {
let stationType = message.stationType
let noticeInfoList = JSON.parse(message.noticeInfo)
let newArr = noticeInfoList.map(v=> {
return {...v, stationType: stationType}
})
let channel = channelList.value.find(i => i.stationId == message.stationId)
channel.logData = [...channel.logData, ...newArr]
emit('refresh')
}
if (![0,2,3].includes(message.noticeType)) {
let channel = channelList.value.find(i => i.stationId == message.stationId)
channel.errNum = channel.errNum + 1
}
};
// Websoket连接错误事件
const websocketOnerror = (res) => {
console.log("WebSocket连接错误");
};
// Websoket断开事件
const websocketClose = (res) => {
console.log("WebSocket断开连接");
reconnect()
};
function reconnect() {
if(state.lockReconnect) return;
state.lockReconnect = true;
//没连接上会一直重连,设置延迟避免请求过多
setTimeout(function () {
console.log("尝试重连...");
initWebSocket();
state.lockReconnect = false;
}, 5000);
}
const loadData = () => {
if (sessionStorage.getItem('storeInfo')) {
let config = JSON.parse(sessionStorage.getItem('storeInfo'))
sysForm.value = {
id: config.id,
storeCode: config.storeCode,
serverIp: config.serverIp,
serverPort: config.serverPort,
isHide: config.isHide
}
channelList.value = []
postAction(state.url.getDevice, {storeCode: JSON.parse(sessionStorage.getItem('storeInfo')).storeCode}).then(res => {
if (res.code !== 99200) return ElMessage.error(res.message);
res.data.map((item, index) => {
channelList.value.push(Object.assign({}, item, { logData: [], errNum: 0 }))
})
initWebSocket()
getAction(state.url.openReader, {storeCode: JSON.parse(sessionStorage.getItem('storeInfo')).storeCode}).then(res => {
})
})
} else {
postAction(state.url.getConfig, {}).then(res => {
if (res.code !== 99200) return ElMessage.error(res.message);
state.storeInfo = res.data[0]
sessionStorage.setItem('storeInfo', JSON.stringify(state.storeInfo))
loadData()
})
}
}
function showChannelSetting() {
postAction(state.url.getDevice, {storeCode: JSON.parse(sessionStorage.getItem('storeInfo')).storeCode, stationId: activeTab.value}).then(res => {
if (res.code !== 99200) return ElMessage.error(res.message);
formData.value = res.data[0]
readerType.value = res.data[0].readerType
title.value = activeTab.value + '号通道配置'
if (res.data[0].readerType == 4) {
power1.value = res.data[0].readerPower.split(',')[0]
power2.value = res.data[0].readerPower.split(',')[1]
power3.value = res.data[0].readerPower.split(',')[2]
power4.value = res.data[0].readerPower.split(',')[3]
}
if (res.data[0].readerType == 8) {
power1.value = res.data[0].readerPower.split(',')[0]
power2.value = res.data[0].readerPower.split(',')[1]
power3.value = res.data[0].readerPower.split(',')[2]
power4.value = res.data[0].readerPower.split(',')[3]
power5.value = res.data[0].readerPower.split(',')[4]
power6.value = res.data[0].readerPower.split(',')[5]
power7.value = res.data[0].readerPower.split(',')[6]
power8.value = res.data[0].readerPower.split(',')[7]
}
visible.value = true
})
}
function handleSubmit() {
if (readerType.value == 4) {
formData.value.readerPower = power1.value + ',' + power2.value + ',' + power3.value + ',' + power4.value
}
if (readerType.value == 8) {
formData.value.readerPower = power1.value + ',' + power2.value + ',' + power3.value + ',' + power4.value + ',' + power5.value + ',' + power6.value + ',' + power7.value + ',' + power8.value
}
postAction(state.url.updateDevice, formData.value).then(res => {
if (res.code !== 99200) return ElMessage.error(res.message);
ElMessage.success(res.message)
formData.value = {}
visible.value = false
})
}
loadData()
return {
...toRefs(state),
sysForm,
channelList,
log,
logData,
formData,
activeTab,
readerType,
activeNames,
title,
visible,
power1,
power2,
power3,
power4,
power5,
power6,
power7,
power8,
loadData,
showChannelSetting,
handleSubmit
}
},
})
</script>
<style lang="less" scoped>
.el-tabs--border-card >.el-tabs__content {
padding: 0px !important;
}
.text {
text-align: center;
font-size: 40px;
}
.head-container {
padding-bottom: 10px;
.filter-item {
display: inline-block;
vertical-align: middle;
margin-bottom: 10px;
margin-left: 6px;
}
}
.title {
font-size: 18px;
font-family: Microsoft YaHei;
font-weight: bold;
color: #303133;
padding-bottom: 17px;
padding-top: 17px;
}
/deep/ .el-form-item--large {
margin-bottom: 0px;
}
/deep/ .el-collapse-item__header.is-active {
border-bottom: 1px solid #ebeef5;
}
/deep/ .el-collapse-item__wrap {
border: none;
}
/deep/ .el-dialog{
display: flex;
flex-direction: column;
margin:0 !important;
position:absolute;
top:50%;
left:50%;
transform:translate(-50%,-50%);
/*height:600px;*/
max-height:calc(100% - 30px);
max-width:calc(100% - 30px);
}
/deep/ .el-dialog .el-dialog__body{
flex:1;
overflow: auto;
}
p {
margin: 0;
padding: 0;
}
.row {
overflow: hidden;
margin-bottom: 22px;
}
.row .col_left {
float: left;
width: 420px;
}
.row .col_right {
float: left;
}
</style>
\ No newline at end of file
<template>
<el-row :gutter="20">
<el-col :span="6">
<el-card>
<el-form label-position="right" size="large" label-width="100px" :model="formData" style="max-width: 460px;height: calc(100vh - 168px);">
<el-form-item label="通道">
<el-select v-model="formData.stationId" style="width: 100%;" filterable placeholder="请选择通道" @change="changeStation">
<el-option v-for="item in bindList" :key="item.stationId" :label="item.stationId" :value="item.stationId"/>
</el-select>
</el-form-item>
<el-form-item label="单号">
<el-select v-model="formData.billNo" style="width: 100%;" filterable clearable placeholder="请选择单号" @change="changeBill">
<el-option v-for="item in billList" :key="item.billNo" :label="item.billName" :value="item.billNo"/>
</el-select>
</el-form-item>
<el-form-item label="品名">
<el-select v-model="formData.goodsCode" style="width: 100%;" filterable clearable placeholder="请选择品名" @change="changeGoods">
<el-option v-for="item in goodsList" :key="item.goodsCode" :label="item.goodsName" :value="item.goodsCode"/>
</el-select>
</el-form-item>
<el-form-item label="号型">
<el-select v-model="formData.modelCode" style="width: 100%;" filterable clearable placeholder="请选择号型" @change="changeModel">
<el-option v-for="item in modelList" :key="item.modelCode" :label="item.modelName" :value="item.modelCode"/>
</el-select>
</el-form-item>
<el-form-item label="单包数量">
<el-input-number v-model="formData.amount" :min="0" :precision="0" style="width: 100%;"/>
</el-form-item>
<div style="text-align: center;">
<el-button type="success" @click="automatic" style="width: 45%">自动</el-button>
<el-button type="primary" @click="manual" style="width: 45%">手动</el-button>
</div>
</el-form>
</el-card>
</el-col>
<el-col :span="18">
<el-card>
<el-table :data="bindList" border size="large" style="width: 100%;height: calc(100vh - 168px);">
<el-table-column type="index" label="序号" width="70" align="center"/>
<el-table-column prop="stationId" label="通道号" align="center"/>
<el-table-column prop="state" label="状态" align="center">
<template #default="scope">
{{scope.row.state === 0 ? '自动' : scope.row.state === 1 ? '手动' : ''}}
</template>
</el-table-column>
<el-table-column prop="billName" label="单号" align="center"/>
<el-table-column prop="goodsName" label="品名" align="center"/>
<el-table-column prop="modelName" label="号型" align="center"/>
<el-table-column prop="amount" label="数量" align="center"/>
</el-table>
</el-card>
</el-col>
</el-row>
</template>
<script>
import { defineComponent, ref, reactive, toRefs, getCurrentInstance } from 'vue'
import { ElMessage } from 'element-plus'
import { postAction } from '@/api/manage'
export default defineComponent({
setup() {
const bindList = ref([])
const channelList = ref([])
const billList = ref([])
const goodsList = ref([])
const modelList = ref([])
const formData = ref({
amount: 1
})
const { proxy } = getCurrentInstance()
const searchData = ref({
pageNo: 1,
pageSize: 10
})
const total = ref(0)
const state = reactive({
url: {
getBindPage: '/bind/getBindPage',
getBillPage: '/bill/getBillPage',
getGoodsPage: '/bill/getGoodsPage',
getModelPage: '/bill/getModelPage',
updateBind: '/bind/updateBind'
}
});
function handleCurrentChange (val) {
searchData.value.pageNo = val
loadData()
}
const loadData = (e) => {
if (sessionStorage.getItem('storeInfo')) {
searchData.value.storeCode = JSON.parse(sessionStorage.getItem('storeInfo')).storeCode
postAction(state.url.getBindPage, searchData.value).then(res => {
if (res.code !== 99200) return ElMessage.error(res.message);
bindList.value = res.data.records
total.value = res.data.totalRows - 0
if(e) {
} else {
if (res.data.records.length > 0) {
formData.value.stationId = res.data.records[0].stationId
formData.value.id = res.data.records[0].id
}
}
})
}
}
const loadSelect = () => {
if (sessionStorage.getItem('storeInfo')) {
postAction(state.url.getBillPage, {pageNo: 1, pageSize: 50, type: 'IN', storeCode: JSON.parse(sessionStorage.getItem('storeInfo')).storeCode}).then(res => {
if (res.code !== 99200) return ElMessage.error(res.message);
billList.value = res.data.records
})
}
}
function changeStation(value) {
if(value) {
formData.value.id = bindList.value.find(i => i.stationId == formData.value.stationId).id
console.log(formData.value.id)
}
}
function changeBill(value) {
goodsList.value = []
formData.value.goodsCode = ''
modelList.value = []
formData.value.modelCode = ''
if (value) {
formData.value.bizBillNo = billList.value.find(i => i.billNo == formData.value.billNo).bizBillNo
formData.value.billName = billList.value.find(i => i.billNo == formData.value.billNo).billName
postAction(state.url.getGoodsPage, {pageNo: 1, pageSize: 50, type: 'IN', storeCode: JSON.parse(sessionStorage.getItem('storeInfo')).storeCode, bizBillNo: formData.value.bizBillNo}).then(res => {
if (res.code !== 99200) return ElMessage.error(res.message);
goodsList.value = res.data.records
})
}
}
function changeGoods(value) {
modelList.value = []
formData.value.modelCode = ''
if (value) {
formData.value.goodsName = goodsList.value.find(i => i.goodsCode == formData.value.goodsCode).goodsName
postAction(state.url.getModelPage, {pageNo: 1, pageSize: 50, type: 'IN', storeCode: JSON.parse(sessionStorage.getItem('storeInfo')).storeCode, bizBillNo: formData.value.bizBillNo, goodsCode: value}).then(res => {
if (res.code !== 99200) return ElMessage.error(res.message);
modelList.value = res.data.records
})
}
}
function changeModel(value) {
if (value) {
formData.value.modelName = modelList.value.find(i => i.modelCode == formData.value.modelCode).modelName
formData.value.skuCode = modelList.value.find(i => i.modelCode == formData.value.modelCode).skuCode
}
}
function automatic() {
formData.value.billNo = ''
formData.value.goodsCode = ''
formData.value.modelCode = ''
formData.value.state = 0
postAction(state.url.updateBind, formData.value).then(res => {
if (res.code !== 99200) return ElMessage.error(res.message);
ElMessage.success(res.message)
loadData(1)
})
}
function manual() {
if (!formData.value.billNo) {
return ElMessage.warning('请选择单号')
}
if (!formData.value.goodsCode) {
return ElMessage.warning('请选择品名')
}
if (!formData.value.modelCode) {
return ElMessage.warning('请选择号型')
}
formData.value.state = 1
postAction(state.url.updateBind, formData.value).then(res => {
if (res.code !== 99200) return ElMessage.error(res.message);
ElMessage.success(res.message)
loadData(1)
})
}
// loadData()
loadSelect()
return {
...toRefs(state),
bindList,
channelList,
billList,
goodsList,
modelList,
formData,
searchData,
total,
handleCurrentChange,
changeStation,
changeBill,
changeGoods,
changeModel,
automatic,
manual,
loadData
}
},
})
</script>
\ No newline at end of file
{
"compilerOptions": {
"target": "ESNext",
"useDefineForClassFields": true,
"module": "ESNext",
"moduleResolution": "Node",
"strict": true,
"jsx": "preserve",
"resolveJsonModule": true,
"isolatedModules": true,
"esModuleInterop": true,
"lib": ["ESNext", "DOM"],
"skipLibCheck": true,
"noEmit": true,
"allowJs": true
},
"include": ["src"],
"references": [
{ "path": "./tsconfig.node.json" }
]
}
{
"compilerOptions": {
"composite": true,
"module": "ESNext",
"moduleResolution": "Node",
"resolveJsonModule": true,
"allowSyntheticDefaultImports": true
},
"include": ["vite.config.ts", "package.json", "electron"]
}
import { rmSync } from 'node:fs'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import electron from 'vite-plugin-electron'
import renderer from 'vite-plugin-electron-renderer'
import pkg from './package.json'
import { fileURLToPath, URL } from 'node:url'
rmSync('dist-electron', { recursive: true, force: true })
const isDevelopment = process.env.NODE_ENV === "development" || !!process.env.VSCODE_DEBUG
const isProduction = process.env.NODE_ENV === "production"
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
electron([
{
// Main-Process entry file of the Electron App.
entry: 'electron/main/index.ts',
onstart(options) {
if (process.env.VSCODE_DEBUG) {
console.log(/* For `.vscode/.debug.script.mjs` */'[startup] Electron App')
} else {
options.startup()
}
},
vite: {
build: {
sourcemap: isDevelopment,
minify: isProduction,
outDir: 'dist-electron/main',
rollupOptions: {
external: Object.keys("dependencies" in pkg ? pkg.dependencies : {}),
},
},
},
},
{
entry: 'electron/preload/index.ts',
onstart(options) {
// Notify the Renderer-Process to reload the page when the Preload-Scripts build is complete,
// instead of restarting the entire Electron App.
options.reload()
},
vite: {
build: {
sourcemap: isDevelopment,
minify: isProduction,
outDir: 'dist-electron/preload',
rollupOptions: {
external: Object.keys("dependencies" in pkg ? pkg.dependencies : {}),
},
},
},
}
]),
// Use Node.js API in the Renderer-process
renderer({
nodeIntegration: true,
}),
],
server: !!process.env.VSCODE_DEBUG ? (() => {
const url = new URL(pkg.debug.env.VITE_DEV_SERVER_URL)
return {
host: url.hostname,
port: +url.port,
}
})() : undefined,
clearScreen: false,
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
}
})
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论