release(custom): i
@@ -1,23 +1,26 @@
|
||||
module.exports = {
|
||||
types: [
|
||||
{ value: 'feat', name:'feat: 新增功能' },
|
||||
{ value: 'fix', name:'fix: 修复bug' },
|
||||
{ value: 'docs', name:'docs: 文档变更' },
|
||||
{ value: 'style', name:'style: 代码格式(不影响功能,例如空格、分号等格式修正)' },
|
||||
{ value: 'refactor', name:'refactor: 代码重构(不包括 bug 修复、功能新增)' },
|
||||
{ value: 'perf', name:'perf: 性能优化' },
|
||||
{ value: 'test', name:'test: 添加、修改测试用例' },
|
||||
{ value: 'build', name:'build: 构建流程、外部依赖变更(如升级 npm 包、修改 脚手架 配置等)' },
|
||||
{ value: 'ci', name:'ci: 修改 CI 配置、脚本' },
|
||||
{ value: 'chore', name:'chore: 对构建过程或辅助工具和库的更改(不影响源文件、测试用例)' },
|
||||
{ value: 'revert', name:'revert: 回滚 commit' },
|
||||
{ value: 'wip', name:'wip: 开发中' },
|
||||
{ value: 'mod', name:'mod: 不确定分类的修改' },
|
||||
{ value: 'release', name:'release: 发布' },
|
||||
{ value: 'feat', name: 'feat: 新增功能' },
|
||||
{ value: 'fix', name: 'fix: 修复bug' },
|
||||
{ value: 'docs', name: 'docs: 文档变更' },
|
||||
{ value: 'style', name: 'style: 代码格式(不影响功能,例如空格、分号等格式修正)' },
|
||||
{ value: 'refactor', name: 'refactor: 代码重构(不包括 bug 修复、功能新增)' },
|
||||
{ value: 'perf', name: 'perf: 性能优化' },
|
||||
{ value: 'test', name: 'test: 添加、修改测试用例' },
|
||||
{
|
||||
value: 'build',
|
||||
name: 'build: 构建流程、外部依赖变更(如升级 npm 包、修改 脚手架 配置等)',
|
||||
},
|
||||
{ value: 'ci', name: 'ci: 修改 CI 配置、脚本' },
|
||||
{ value: 'chore', name: 'chore: 对构建过程或辅助工具和库的更改(不影响源文件、测试用例)' },
|
||||
{ value: 'revert', name: 'revert: 回滚 commit' },
|
||||
{ value: 'wip', name: 'wip: 开发中' },
|
||||
{ value: 'mod', name: 'mod: 不确定分类的修改' },
|
||||
{ value: 'release', name: 'release: 发布' },
|
||||
],
|
||||
scopes: [
|
||||
['custom', '自定义'],
|
||||
['projects', '项目搭建'],
|
||||
['projects', '项目搭建'],
|
||||
['components', '组件相关'],
|
||||
['utils', 'utils 相关'],
|
||||
['styles', '样式相关'],
|
||||
@@ -26,7 +29,7 @@ module.exports = {
|
||||
].map(([value, description]) => {
|
||||
return {
|
||||
value,
|
||||
name: `${value.padEnd(30)} (${description})`
|
||||
name: `${value.padEnd(30)} (${description})`,
|
||||
}
|
||||
}),
|
||||
messages: {
|
||||
@@ -37,9 +40,9 @@ module.exports = {
|
||||
body: '填写更加详细的变更描述(可选)。使用 "|" 换行:',
|
||||
breaking: '列举非兼容性重大的变更(可选):',
|
||||
footer: '列举出所有变更的 Issues Closed(可选)。 例如: #31, #34:',
|
||||
confirmCommit: '确认提交?'
|
||||
confirmCommit: '确认提交?',
|
||||
},
|
||||
allowBreakingChanges: ['feat', 'fix'],
|
||||
subjectLimit: 100,
|
||||
breaklineChar: '|'
|
||||
breaklineChar: '|',
|
||||
}
|
||||
|
||||
14
.env.test
@@ -1,7 +1,7 @@
|
||||
VITE_PUBLIC_PATH = '/'
|
||||
|
||||
# 是否启用MOCK
|
||||
VITE_USE_MOCK = true
|
||||
|
||||
# base api
|
||||
VITE_BASE_API = '/api'
|
||||
VITE_PUBLIC_PATH = '/static/mer'
|
||||
|
||||
# 是否启用MOCK
|
||||
VITE_USE_MOCK = true
|
||||
|
||||
# base api
|
||||
VITE_BASE_API = 'https://test.wanzhuanyongcheng.cn/store'
|
||||
6
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
</profile>
|
||||
</component>
|
||||
6
.idea/jsLibraryMappings.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="JavaScriptLibraryMappings">
|
||||
<includedPredefinedLibrary name="Node.js Core" />
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/jsLinters/eslint.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="EslintConfiguration">
|
||||
<option name="fix-on-save" value="true" />
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/prettier.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="PrettierConfiguration">
|
||||
<option name="myConfigurationMode" value="AUTOMATIC" />
|
||||
</component>
|
||||
</project>
|
||||
2
.vscode/extensions.json
vendored
@@ -4,6 +4,6 @@
|
||||
"antfu.iconify",
|
||||
"mikestead.dotenv",
|
||||
"sdras.vue-vscode-snippets",
|
||||
"cipchk.cssrem",
|
||||
"cipchk.cssrem"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import Components from 'unplugin-vue-components/vite'
|
||||
import { NaiveUiResolver } from 'unplugin-vue-components/resolvers'
|
||||
import { FileSystemIconLoader } from 'unplugin-icons/loaders'
|
||||
import IconsResolver from 'unplugin-icons/resolver'
|
||||
import mkcert from 'vite-plugin-mkcert'
|
||||
|
||||
/**
|
||||
* * unplugin-icons插件,自动引入iconify图标
|
||||
@@ -43,4 +44,5 @@ export default [
|
||||
inject: 'body-last',
|
||||
customDomId: '__CUSTOM_SVG_ICON__',
|
||||
}),
|
||||
mkcert(),
|
||||
]
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
推荐阅读作者在掘金的文章:
|
||||
|
||||
[保熟的UnoCSS使用指北,优雅使用antfu大佬的原子化CSS](https://juejin.cn/post/7142466784971456548)
|
||||
[保熟的 UnoCSS 使用指北,优雅使用 antfu 大佬的原子化 CSS](https://juejin.cn/post/7142466784971456548)
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
`<icon-[iconify图标名称]`
|
||||
|
||||
```html
|
||||
<icon-ant-design:fullscreen-exit-outlined />
|
||||
<icon-ant-design:fullscreen-exit-outlined />
|
||||
<icon-ant-design:fullscreen-outlined />
|
||||
```
|
||||
|
||||
@@ -37,4 +37,4 @@
|
||||
<TheIcon icon="logo" type="custom" />
|
||||
```
|
||||
|
||||
封装组件参看 src/components/icon
|
||||
封装组件参看 src/components/icon
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
## 安装pnpm
|
||||
## 安装 pnpm
|
||||
|
||||
### 使用Corepack安装(推荐)
|
||||
### 使用 Corepack 安装(推荐)
|
||||
|
||||
从 v16.13 开始,Node.js 发布了 Corepack 来管理包管理器。 这是一项实验性功能,需要通过运行如下脚本来启用它:
|
||||
|
||||
@@ -8,17 +8,19 @@
|
||||
npx corepack enable // 可能需要管理员权限
|
||||
```
|
||||
|
||||
这将自动在您的系统上安装 pnpm。 但是,它可能不是最新版本的 pnpm。 若要升级,请检查[最新的 pnpm 版本](https://github.com/pnpm/pnpm/releases/latest) 并运行,如 7.14.0
|
||||
这将自动在您的系统上安装 pnpm。 但是,它可能不是最新版本的 pnpm。 若要升级,请检查[最新的 pnpm 版本](https://github.com/pnpm/pnpm/releases/latest) 并运行,如 7.14.0
|
||||
|
||||
```
|
||||
corepack prepare pnpm@7.14.0 --activate
|
||||
```
|
||||
|
||||
如果是 Node.js v16.17 或者更新的版本,可以直接安装最新版本的 pnpm
|
||||
|
||||
```
|
||||
corepack prepare pnpm@latest --activate
|
||||
```
|
||||
|
||||
### 使用npm安装
|
||||
### 使用 npm 安装
|
||||
|
||||
```
|
||||
npm i -g pnpm
|
||||
@@ -29,4 +31,4 @@ npm i -g pnpm
|
||||
```
|
||||
npm uninstall -g pnpm
|
||||
npm i -g pnpm
|
||||
```
|
||||
```
|
||||
|
||||
34
package.json
@@ -11,7 +11,8 @@
|
||||
"lint:fix": "eslint --fix --ext .js,.vue .",
|
||||
"lint:staged": "lint-staged",
|
||||
"prepare": "husky install",
|
||||
"preview": "vite preview"
|
||||
"preview": "vite preview",
|
||||
"lf": "npx prettier --write --end-of-line lf ."
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.{js,vue}": [
|
||||
@@ -31,28 +32,28 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@unocss/eslint-config": "^0.55.3",
|
||||
"@vueuse/core": "^10.4.0",
|
||||
"@unocss/eslint-config": "^0.55.7",
|
||||
"@vueuse/core": "^10.5.0",
|
||||
"@wangeditor/editor": "^5.1.23",
|
||||
"@wangeditor/editor-for-vue": "5.1.12",
|
||||
"axios": "^1.5.0",
|
||||
"dayjs": "^1.11.9",
|
||||
"axios": "^1.5.1",
|
||||
"dayjs": "^1.11.10",
|
||||
"lodash-es": "^4.17.21",
|
||||
"md-editor-v3": "^4.4.0",
|
||||
"md-editor-v3": "^4.7.0",
|
||||
"mockjs": "^1.1.0",
|
||||
"pinia": "^2.1.6",
|
||||
"vite": "^4.4.9",
|
||||
"vite": "^4.4.11",
|
||||
"vue": "3.3.4",
|
||||
"vue-router": "^4.2.4",
|
||||
"vue-router": "^4.2.5",
|
||||
"xlsx": "^0.18.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@commitlint/cli": "^17.7.1",
|
||||
"@commitlint/cli": "^17.7.2",
|
||||
"@commitlint/config-conventional": "^17.7.0",
|
||||
"@iconify/json": "^2.2.106",
|
||||
"@iconify/json": "^2.2.126",
|
||||
"@iconify/vue": "^4.1.1",
|
||||
"@unocss/preset-rem-to-px": "^0.55.3",
|
||||
"@vitejs/plugin-vue": "^4.3.3",
|
||||
"@unocss/preset-rem-to-px": "^0.55.7",
|
||||
"@vitejs/plugin-vue": "^4.4.0",
|
||||
"@vue/compiler-sfc": "^3.3.4",
|
||||
"@zclzone/eslint-config": "^0.0.4",
|
||||
"chalk": "^5.3.0",
|
||||
@@ -64,15 +65,16 @@
|
||||
"fs-extra": "^11.1.1",
|
||||
"husky": "^8.0.3",
|
||||
"lint-staged": "^14.0.1",
|
||||
"naive-ui": "^2.34.4",
|
||||
"naive-ui": "^2.35.0",
|
||||
"rollup-plugin-visualizer": "^5.9.2",
|
||||
"sass": "^1.66.1",
|
||||
"sass": "^1.69.0",
|
||||
"unocss": "0.55.3",
|
||||
"unplugin-auto-import": "^0.16.6",
|
||||
"unplugin-icons": "^0.16.5",
|
||||
"unplugin-vue-components": "^0.25.1",
|
||||
"unplugin-icons": "^0.16.6",
|
||||
"unplugin-vue-components": "^0.25.2",
|
||||
"vite-plugin-compression": "^0.5.1",
|
||||
"vite-plugin-html": "^3.2.0",
|
||||
"vite-plugin-mkcert": "^1.16.0",
|
||||
"vite-plugin-mock": "2.9.6",
|
||||
"vite-plugin-svg-icons": "^2.0.1"
|
||||
}
|
||||
|
||||
15687
pnpm-lock.yaml
generated
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 20 KiB |
2233
public/favicon.svg
|
Before Width: | Height: | Size: 825 B After Width: | Height: | Size: 170 KiB |
|
Before Width: | Height: | Size: 8.4 KiB After Width: | Height: | Size: 20 KiB |
@@ -3,4 +3,13 @@ import { request } from '@/utils'
|
||||
export default {
|
||||
getUser: () => request.get('/user'),
|
||||
refreshToken: () => request.post('/auth/refreshToken', null, { noNeedTip: true }),
|
||||
// 获取商家信息
|
||||
getMerchantInfo: () => request.post('/info'),
|
||||
// 上传图片
|
||||
uploadImg: (data) =>
|
||||
request.post('/upload', data, {
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
}),
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 8.4 KiB After Width: | Height: | Size: 20 KiB |
@@ -21,7 +21,7 @@ import '@wangeditor/editor/dist/css/style.css' // 引入 css
|
||||
|
||||
import { onBeforeUnmount, shallowRef, ref } from 'vue'
|
||||
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
|
||||
import { getToken } from '@/utils'
|
||||
import api from '@/api'
|
||||
|
||||
const props = defineProps({
|
||||
valueHtml: {
|
||||
@@ -36,64 +36,40 @@ const editorRef = shallowRef()
|
||||
|
||||
const _ref = ref(null)
|
||||
|
||||
const Token = getToken()
|
||||
|
||||
const toolbarConfig = {}
|
||||
|
||||
const editorConfig = { placeholder: '请输入商品详情...', MENU_CONF: {} }
|
||||
|
||||
const htmlValue = computed({
|
||||
get() {
|
||||
console.log('get', props.valueHtml)
|
||||
return props.valueHtml
|
||||
},
|
||||
set(value) {
|
||||
console.log('set', props.valueHtml)
|
||||
emit('update:valueHtml', value)
|
||||
},
|
||||
})
|
||||
|
||||
editorConfig.MENU_CONF['uploadImage'] = {
|
||||
// 其他配置...
|
||||
// 小于该值就插入 base64 格式(而不上传),默认为 0
|
||||
fieldName: 'file',
|
||||
server: '/store/upload',
|
||||
allowedFileTypes: ['image/*'],
|
||||
headers: {
|
||||
Authorization: `Bearer ${Token}`,
|
||||
},
|
||||
base64LimitSize: 5 * 1024, // 5kb
|
||||
// 超时时间,默认为 10 秒
|
||||
timeout: 5 * 1000, // 5 秒
|
||||
// 自定义插入图片
|
||||
customInsert(res, insertFn) {
|
||||
if (res.code === 200) {
|
||||
console.log(res)
|
||||
$message.success('上传成功')
|
||||
insertFn(res.data.data)
|
||||
}
|
||||
|
||||
async customUpload(file, insertFn) {
|
||||
await upFile(file, insertFn)
|
||||
},
|
||||
}
|
||||
|
||||
editorConfig.MENU_CONF['uploadVideo'] = {
|
||||
server: '/store/upload',
|
||||
fieldName: 'file',
|
||||
allowedFileTypes: ['video/*'],
|
||||
headers: {
|
||||
Authorization: `Bearer ${Token}`,
|
||||
},
|
||||
// 单个文件上传成功之后
|
||||
customInsert(res, insertFn) {
|
||||
console.log(res)
|
||||
|
||||
// 如果成功了,就把视频的地址,插入到编辑器中
|
||||
insertFn(res.data.data)
|
||||
async customUpload(file, insertFn) {
|
||||
await upFile(file, insertFn)
|
||||
},
|
||||
}
|
||||
|
||||
// 组件销毁时,也及时销毁编辑器
|
||||
onBeforeUnmount(() => {
|
||||
console.log('销毁')
|
||||
const editor = editorRef.value
|
||||
if (editor == null) return
|
||||
editor.destroy()
|
||||
@@ -105,6 +81,13 @@ const handleCreated = (editor) => {
|
||||
_ref.value.style.zIndex = 10
|
||||
})
|
||||
}
|
||||
|
||||
const upFile = async (file, insertFn) => {
|
||||
const formData = new FormData()
|
||||
formData.append('file', file)
|
||||
const res = await api.uploadImg(formData)
|
||||
insertFn(res.data.data)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
<template>
|
||||
<n-upload
|
||||
v-model:file-list="List"
|
||||
action="/store/upload"
|
||||
:headers="headers"
|
||||
:max="max"
|
||||
list-type="image-card"
|
||||
:custom-request="customRequest"
|
||||
:multiple="multiple"
|
||||
@before-upload="beforeUpload"
|
||||
@finish="handleFinish"
|
||||
@error="handleError"
|
||||
>
|
||||
点击上传
|
||||
@@ -14,9 +13,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { getToken } from '@/utils'
|
||||
|
||||
const token = getToken()
|
||||
import api from '@/api'
|
||||
|
||||
const prop = defineProps({
|
||||
list: {
|
||||
@@ -27,14 +24,14 @@ const prop = defineProps({
|
||||
type: Number,
|
||||
default: 1,
|
||||
},
|
||||
multiple: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update:list'])
|
||||
|
||||
const headers = ref({
|
||||
Authorization: `Bearer ${token}`,
|
||||
})
|
||||
|
||||
const List = computed({
|
||||
get() {
|
||||
return prop.list
|
||||
@@ -44,12 +41,6 @@ const List = computed({
|
||||
},
|
||||
})
|
||||
|
||||
const handleFinish = ({ file, event }) => {
|
||||
const res = JSON.parse(event.target.response)
|
||||
file.url = res.data.data
|
||||
return file
|
||||
}
|
||||
|
||||
const handleError = () => {
|
||||
$message.error('上传失败')
|
||||
}
|
||||
@@ -62,6 +53,14 @@ const beforeUpload = (data) => {
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
const customRequest = async ({ file, onFinish }) => {
|
||||
const formData = new FormData()
|
||||
formData.append('file', file.file)
|
||||
const res = await api.uploadImg(formData)
|
||||
$message.success(res.msg)
|
||||
onFinish(res.data.data)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
|
||||
@@ -109,6 +109,7 @@ function handleMenuSelect(key, item) {
|
||||
left: 5px;
|
||||
right: 5px;
|
||||
}
|
||||
|
||||
&.n-menu-item-content--selected,
|
||||
&:hover {
|
||||
&::before {
|
||||
|
||||
@@ -11,6 +11,9 @@ export function createPermissionGuard(router) {
|
||||
return { path: 'login', query: { ...to.query, redirect: to.path } }
|
||||
}
|
||||
|
||||
/** 单点登录的情况 */
|
||||
if (to.query.tk) return true
|
||||
|
||||
/** 有token的情况 */
|
||||
if (to.path === '/login') return { path: '/' }
|
||||
|
||||
|
||||
@@ -18,7 +18,10 @@ export const useUserStore = defineStore('user', {
|
||||
return this.userInfo?.name
|
||||
},
|
||||
avatar() {
|
||||
return this.userInfo?.avatar
|
||||
return (
|
||||
this.userInfo?.avatar ||
|
||||
'https://pic3.58cdn.com.cn/nowater/webim/big/n_v21bc7874294754e63a22b80febac9cf51.jpg'
|
||||
)
|
||||
},
|
||||
role() {
|
||||
return this.userInfo?.role || []
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { lStorage } from '@/utils'
|
||||
import api from '@/api'
|
||||
|
||||
const TOKEN_CODE = 'mer_token'
|
||||
const DURATION = 6 * 60 * 60
|
||||
@@ -17,17 +16,17 @@ export function removeToken() {
|
||||
}
|
||||
|
||||
export async function refreshAccessToken() {
|
||||
const tokenItem = lStorage.getItem(TOKEN_CODE)
|
||||
if (!tokenItem) {
|
||||
return
|
||||
}
|
||||
const { time } = tokenItem
|
||||
// token生成或者刷新后30分钟内不执行刷新
|
||||
if (new Date().getTime() - time <= 1000 * 60 * 30) return
|
||||
try {
|
||||
const res = await api.refreshToken()
|
||||
setToken(res.data.token)
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
}
|
||||
// const tokenItem = lStorage.getItem(TOKEN_CODE)
|
||||
// if (!tokenItem) {
|
||||
// return
|
||||
// }
|
||||
// const { time } = tokenItem
|
||||
// // token生成或者刷新后30分钟内不执行刷新
|
||||
// if (new Date().getTime() - time <= 1000 * 60 * 30) return
|
||||
// try {
|
||||
// const res = await api.refreshToken()
|
||||
// setToken(res.data.token)
|
||||
// } catch (error) {
|
||||
// console.error(error)
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ export function resResolve(response) {
|
||||
const code = data?.code ?? status
|
||||
|
||||
/** 根据code处理对应的操作,并返回处理后的message */
|
||||
const message = resolveResError(code, data?.message ?? statusText)
|
||||
const message = resolveResError(code, data?.msg ?? statusText)
|
||||
|
||||
/** 需要错误提醒 */
|
||||
!config.noNeedTip && window.$message?.error(message)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { request } from '@/utils'
|
||||
|
||||
export default {
|
||||
getGoodClass: (data) => request.post('/goods/class', data),
|
||||
getGoodClass: (data) => request.post('/classify', data),
|
||||
addGoods: (data) => request.post('/goods/edit', data),
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<Upload v-model:list="model.cover" />
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi :span="12" label="商品轮播图:" path="rotation">
|
||||
<Upload v-model:list="model.rotation" :max="5" />
|
||||
<Upload v-model:list="model.rotation" :max="5" multiple />
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi :span="12" label="商品价格:" path="number">
|
||||
<n-input-number v-model:value="model.number" placeholder="输入商品价格" />
|
||||
@@ -31,11 +31,12 @@
|
||||
<n-form-item-gi :span="12" label="商品库存:" path="stock">
|
||||
<n-input-number v-model:value="model.stock" placeholder="输入商品库存" />
|
||||
</n-form-item-gi>
|
||||
|
||||
<n-form-item-gi :span="12" label="商品简介:" path="profile">
|
||||
<n-input v-model:value="model.profile" type="textarea" placeholder="输入商品简介" />
|
||||
</n-form-item-gi>
|
||||
|
||||
<n-form-item-gi :span="12" label="上架状态:" path="state">
|
||||
<n-switch v-model:value="model.state" :checked-value="1" :unchecked-value="2" />
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi :span="12" label="商品详情:" path="details">
|
||||
<Editor v-model:valueHtml="model.details" />
|
||||
</n-form-item-gi>
|
||||
@@ -67,6 +68,7 @@ const model = ref({
|
||||
stock: null,
|
||||
number: null,
|
||||
market_num: null,
|
||||
state: 2,
|
||||
})
|
||||
|
||||
const rules = {
|
||||
|
||||
7
src/views/goods/class/api.js
Normal file
@@ -0,0 +1,7 @@
|
||||
import { request } from '@/utils'
|
||||
|
||||
export default {
|
||||
getGoodClass: (data) => request.post('/classify', data),
|
||||
// 添加或修改
|
||||
addGoodClass: (data) => request.post('/classify/edit', data),
|
||||
}
|
||||
171
src/views/goods/class/index.vue
Normal file
@@ -0,0 +1,171 @@
|
||||
<template>
|
||||
<CommonPage show-footer :title="$route.title">
|
||||
<n-button type="primary" @click="addClass(1)">添加商品分类</n-button>
|
||||
<n-data-table
|
||||
class="mt-10"
|
||||
:loading="loading"
|
||||
:columns="columns"
|
||||
:data="data"
|
||||
:pagination="pagination"
|
||||
:bordered="false"
|
||||
remote
|
||||
/>
|
||||
<!-- 添加/编辑对话框 -->
|
||||
<n-modal v-model:show="showModal">
|
||||
<n-card
|
||||
style="width: 500px"
|
||||
:title="showModalTitle"
|
||||
:bordered="false"
|
||||
size="huge"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
>
|
||||
<n-form ref="formRef" :model="model" :rules="rules" label-placement="left">
|
||||
<n-grid :cols="24" :x-gap="24">
|
||||
<n-form-item-gi label="商品分类:" :span="14" path="name">
|
||||
<n-input v-model:value="model.name" placeholder="请输入商品分类" />
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi label="是否显示:" :span="14" path="status">
|
||||
<n-switch v-model:value="model.status" :unchecked-value="2" :checked-value="1" />
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi :span="14">
|
||||
<div class="m-auto">
|
||||
<n-button type="primary" @click="submit">提交</n-button>
|
||||
<n-button ml-10 @click="clear">取消</n-button>
|
||||
</div>
|
||||
</n-form-item-gi>
|
||||
</n-grid>
|
||||
</n-form>
|
||||
</n-card>
|
||||
</n-modal>
|
||||
</CommonPage>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import api from './api.js'
|
||||
import { NTag, NButton } from 'naive-ui'
|
||||
|
||||
const loading = ref(false)
|
||||
|
||||
const data = ref([])
|
||||
|
||||
const showModal = ref(false)
|
||||
|
||||
const showModalTitle = ref('')
|
||||
|
||||
const model = ref({
|
||||
name: '',
|
||||
status: 2,
|
||||
})
|
||||
|
||||
const columns = ref([
|
||||
{
|
||||
title: '分类名称',
|
||||
key: 'name',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '是否显示',
|
||||
slot: 'status',
|
||||
align: 'center',
|
||||
render: (row) => {
|
||||
return h(
|
||||
NTag,
|
||||
{
|
||||
type: row.status === 1 ? 'success' : 'warning',
|
||||
bordered: false,
|
||||
},
|
||||
{
|
||||
default: () => (row.status === 1 ? '显示' : '隐藏'),
|
||||
}
|
||||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
slot: 'action',
|
||||
align: 'center',
|
||||
render: (row) => {
|
||||
return [
|
||||
h(
|
||||
NButton,
|
||||
{
|
||||
text: true,
|
||||
size: 'small',
|
||||
type: 'primary',
|
||||
onClick: () => {
|
||||
addClass(2, row)
|
||||
},
|
||||
},
|
||||
{
|
||||
default: () => '编辑',
|
||||
}
|
||||
),
|
||||
]
|
||||
},
|
||||
},
|
||||
])
|
||||
|
||||
const formRef = ref(null)
|
||||
|
||||
const rules = {
|
||||
name: {
|
||||
required: true,
|
||||
message: '请输入商品分类',
|
||||
trigger: 'blur',
|
||||
},
|
||||
}
|
||||
|
||||
const pagination = ref({
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
itemCount: 0,
|
||||
onChange: (page) => {
|
||||
pagination.value.page = page
|
||||
get_data()
|
||||
},
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
get_data()
|
||||
})
|
||||
|
||||
const get_data = async () => {
|
||||
loading.value = true
|
||||
const res = await api.getGoodClass({
|
||||
PageNum: pagination.value.page,
|
||||
PageSize: pagination.value.pageSize,
|
||||
})
|
||||
data.value = res.data.data || []
|
||||
pagination.value.itemCount = res.data.total
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
const addClass = (e, row = {}) => {
|
||||
showModalTitle.value = e === 1 ? '添加商品分类' : '编辑商品分类'
|
||||
if (e === 2) model.value = { ...row }
|
||||
showModal.value = true
|
||||
}
|
||||
|
||||
const submit = () => {
|
||||
formRef.value?.validate(async (errors) => {
|
||||
if (!errors) {
|
||||
const res = await api.addGoodClass(model.value)
|
||||
$message.success(res.msg)
|
||||
clear()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const clear = () => {
|
||||
formRef.value.restoreValidation()
|
||||
model.value = {
|
||||
name: '',
|
||||
status: 2,
|
||||
}
|
||||
showModal.value = false
|
||||
get_data()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
@@ -2,5 +2,5 @@ import { request } from '@/utils'
|
||||
|
||||
export default {
|
||||
getGoods: (data) => request.post('/goods', data),
|
||||
getGoodClass: (data) => request.post('/goods/class', data),
|
||||
getGoodClass: (data) => request.post('/classify', data),
|
||||
}
|
||||
|
||||
@@ -14,8 +14,9 @@
|
||||
|
||||
<script setup>
|
||||
import { useRouter } from 'vue-router'
|
||||
import { NButton, NEllipsis } from 'naive-ui'
|
||||
import { NButton, NEllipsis, NImage, NSwitch } from 'naive-ui'
|
||||
import api from './api'
|
||||
import api1 from '../add/api'
|
||||
import { useGoodsStore } from '@/store/modules/goods'
|
||||
|
||||
const loading = ref(false)
|
||||
@@ -31,12 +32,9 @@ const columns = ref([
|
||||
align: 'center',
|
||||
slot: 'cover',
|
||||
render(row) {
|
||||
return h('img', {
|
||||
return h(NImage, {
|
||||
width: '50',
|
||||
src: row.cover,
|
||||
style: {
|
||||
width: '30px',
|
||||
height: '30px',
|
||||
},
|
||||
})
|
||||
},
|
||||
},
|
||||
@@ -74,13 +72,34 @@ const columns = ref([
|
||||
key: 'stock',
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
title: '审核状态',
|
||||
align: 'center',
|
||||
slot: 'status',
|
||||
render(row) {
|
||||
return h('span', row.status === 1 ? '已审核' : row.status === 2 ? '已拒绝' : '待审核')
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '是否上架',
|
||||
align: 'center',
|
||||
slot: 'state',
|
||||
render(row) {
|
||||
return [
|
||||
h(NSwitch, {
|
||||
checkedValue: 1,
|
||||
uncheckedValue: 2,
|
||||
value: row.state,
|
||||
onUpdateValue: async (val) => {
|
||||
await api1.addGoods({
|
||||
...row,
|
||||
state: val,
|
||||
})
|
||||
getList()
|
||||
},
|
||||
}),
|
||||
]
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '备注',
|
||||
key: 'notes',
|
||||
@@ -91,19 +110,17 @@ const columns = ref([
|
||||
align: 'center',
|
||||
slot: 'action',
|
||||
render(row) {
|
||||
if (row.status === 1 || row.status === 2) {
|
||||
return [
|
||||
h(
|
||||
NButton,
|
||||
{
|
||||
type: 'primary',
|
||||
size: 'small',
|
||||
onClick: () => toEdit(row),
|
||||
},
|
||||
() => '编辑'
|
||||
),
|
||||
]
|
||||
}
|
||||
return [
|
||||
h(
|
||||
NButton,
|
||||
{
|
||||
type: 'primary',
|
||||
size: 'small',
|
||||
onClick: () => toEdit(row),
|
||||
},
|
||||
() => '编辑'
|
||||
),
|
||||
]
|
||||
},
|
||||
},
|
||||
])
|
||||
|
||||
@@ -5,6 +5,11 @@ export default {
|
||||
path: '/goods',
|
||||
component: Layout,
|
||||
redirect: '/goods_list',
|
||||
meta: {
|
||||
title: '商品管理',
|
||||
icon: 'mdi:account-multiple',
|
||||
order: 10,
|
||||
},
|
||||
children: [
|
||||
{
|
||||
name: 'Goodslist',
|
||||
@@ -13,7 +18,17 @@ export default {
|
||||
meta: {
|
||||
title: '商品列表',
|
||||
icon: 'mdi:account-multiple',
|
||||
order: 10,
|
||||
order: 4,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Goodsclass',
|
||||
path: 'goods_class',
|
||||
component: () => import('./class/index.vue'),
|
||||
meta: {
|
||||
title: '商品分类',
|
||||
icon: 'mdi:account-multiple',
|
||||
order: 4,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -67,6 +67,9 @@ import { useStorage } from '@vueuse/core'
|
||||
import bgImg from '@/assets/images/login_bg.webp'
|
||||
import api from './api'
|
||||
import { addDynamicRoutes } from '@/router'
|
||||
import { useUserStore } from '@/store'
|
||||
|
||||
const userStore = useUserStore()
|
||||
|
||||
const title = import.meta.env.VITE_TITLE
|
||||
|
||||
@@ -80,6 +83,26 @@ const loginInfo = ref({
|
||||
|
||||
initLoginInfo()
|
||||
|
||||
const easyLogin = async () => {
|
||||
userStore.logout()
|
||||
if (query.tk && query.type) {
|
||||
console.log(query)
|
||||
$message.success('登录成功')
|
||||
setToken(query.tk)
|
||||
window.localStorage.setItem('type', query.type)
|
||||
await addDynamicRoutes()
|
||||
if (query.redirect) {
|
||||
const path = query.redirect
|
||||
Reflect.deleteProperty(query, 'redirect')
|
||||
router.push({ path, query })
|
||||
} else {
|
||||
router.push('/')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
easyLogin()
|
||||
|
||||
function initLoginInfo() {
|
||||
const localLoginInfo = lStorage.get('loginInfo')
|
||||
if (localLoginInfo) {
|
||||
|
||||
@@ -1,6 +1,72 @@
|
||||
<template>
|
||||
<CommonPage show-footer :title="$route.title">
|
||||
<n-row gutter="12">
|
||||
<n-col :span="24">
|
||||
<div flex>
|
||||
<n-card w-500>
|
||||
<n-statistic label="订单流水" tabular-nums>
|
||||
<n-number-animation :from="0" :to="cardData.total" />
|
||||
</n-statistic>
|
||||
</n-card>
|
||||
<n-card ml-10 w-500>
|
||||
<n-statistic label="订单佣金" tabular-nums>
|
||||
<n-number-animation :from="0" :to="cardData.service" />
|
||||
</n-statistic>
|
||||
</n-card>
|
||||
<n-card ml-10 w-500>
|
||||
<n-statistic label="订单数量" tabular-nums>
|
||||
<n-number-animation :from="0" :to="cardData.count" />
|
||||
</n-statistic>
|
||||
</n-card>
|
||||
</div>
|
||||
</n-col>
|
||||
<n-col :span="24" mt-10>
|
||||
<div>
|
||||
<span>订单状态:</span>
|
||||
<n-radio-group v-model:value="queryData.status">
|
||||
<n-radio-button
|
||||
v-for="song in songs"
|
||||
:key="song.value"
|
||||
:value="song.value"
|
||||
:label="song.label"
|
||||
/>
|
||||
</n-radio-group>
|
||||
</div>
|
||||
</n-col>
|
||||
<n-col :span="24">
|
||||
<div mt-10 flex items-center>
|
||||
<div w-100>关键字搜索:</div>
|
||||
<n-input-group>
|
||||
<n-select
|
||||
v-model:value="queryData.selectKey"
|
||||
:style="{ width: '7%' }"
|
||||
:options="selectOptions"
|
||||
placeholder="请选择"
|
||||
/>
|
||||
<n-input v-model:value="queryData.word" :style="{ width: '20%' }" />
|
||||
</n-input-group>
|
||||
</div>
|
||||
</n-col>
|
||||
<n-col :span="10">
|
||||
<div mt-10 flex items-center>
|
||||
<span w-100>订单时间:</span>
|
||||
<n-date-picker
|
||||
v-model:formatted-value="queryData.time"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
type="datetimerange"
|
||||
clearable
|
||||
/>
|
||||
</div>
|
||||
</n-col>
|
||||
<n-col :span="24">
|
||||
<div mt-10>
|
||||
<n-button type="primary" @click="getList">搜索</n-button>
|
||||
<n-button ml-10 @click="clear">重置</n-button>
|
||||
</div>
|
||||
</n-col>
|
||||
</n-row>
|
||||
<n-data-table
|
||||
class="mt-5"
|
||||
:loading="loading"
|
||||
:columns="columns"
|
||||
:data="data"
|
||||
@@ -13,9 +79,55 @@
|
||||
|
||||
<script setup>
|
||||
import api from './api'
|
||||
import { NEllipsis } from 'naive-ui'
|
||||
|
||||
const loading = ref(false)
|
||||
|
||||
const queryData = ref({
|
||||
status: '',
|
||||
time: null,
|
||||
word: '',
|
||||
selectKey: null,
|
||||
})
|
||||
|
||||
const songs = ref([
|
||||
{
|
||||
value: 1,
|
||||
label: '待付款',
|
||||
},
|
||||
{
|
||||
value: 2,
|
||||
label: '待核销',
|
||||
},
|
||||
{
|
||||
value: 3,
|
||||
label: '已核销',
|
||||
},
|
||||
{
|
||||
value: 4,
|
||||
label: '已过期',
|
||||
},
|
||||
])
|
||||
|
||||
const selectOptions = ref([
|
||||
{
|
||||
value: 0,
|
||||
label: '商品名称',
|
||||
},
|
||||
{
|
||||
value: 1,
|
||||
label: '用户昵称',
|
||||
},
|
||||
{
|
||||
value: 2,
|
||||
label: '手机号',
|
||||
},
|
||||
{
|
||||
value: 3,
|
||||
label: '订单号',
|
||||
},
|
||||
])
|
||||
|
||||
const columns = ref([
|
||||
{
|
||||
title: '订单号',
|
||||
@@ -28,15 +140,41 @@ const columns = ref([
|
||||
key: 'user_name',
|
||||
},
|
||||
{
|
||||
title: '商品名称',
|
||||
title: '手机号',
|
||||
align: 'center',
|
||||
key: 'goods_name',
|
||||
key: 'phone',
|
||||
},
|
||||
{
|
||||
title: '商品价格',
|
||||
title: '商品名称',
|
||||
align: 'center',
|
||||
slot: 'goods_name',
|
||||
render: (row) => {
|
||||
return h(
|
||||
NEllipsis,
|
||||
{
|
||||
style: 'max-width: 240px',
|
||||
},
|
||||
{
|
||||
default: () => row.goods_name,
|
||||
}
|
||||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '商品数量',
|
||||
align: 'center',
|
||||
key: 'count',
|
||||
},
|
||||
{
|
||||
title: '商品总价',
|
||||
align: 'center',
|
||||
key: 'number',
|
||||
},
|
||||
{
|
||||
title: '订单佣金',
|
||||
align: 'center',
|
||||
key: 'commission',
|
||||
},
|
||||
{
|
||||
title: '订单状态',
|
||||
align: 'center',
|
||||
@@ -55,17 +193,33 @@ const columns = ref([
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
title: '下单时间',
|
||||
align: 'center',
|
||||
slot: 'action',
|
||||
render(row) {
|
||||
console.log(row)
|
||||
},
|
||||
key: 'add_time',
|
||||
},
|
||||
{
|
||||
title: '核销时间',
|
||||
align: 'center',
|
||||
key: 'cancel_time',
|
||||
},
|
||||
// {
|
||||
// title: '操作',
|
||||
// align: 'center',
|
||||
// slot: 'action',
|
||||
// render() {
|
||||
// // console.log(row)
|
||||
// },
|
||||
// },
|
||||
])
|
||||
|
||||
const data = ref([])
|
||||
|
||||
const cardData = ref({
|
||||
total: 0,
|
||||
service: 0,
|
||||
count: 0,
|
||||
})
|
||||
|
||||
const pagination = ref({
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
@@ -88,18 +242,51 @@ onMounted(() => {
|
||||
const getList = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const query_data = {
|
||||
Status: queryData.value.status || '',
|
||||
StartTime: queryData.value.time === null ? '' : queryData.value.time[0] || '',
|
||||
EndTime: queryData.value.time === null ? '' : queryData.value.time[1] || '',
|
||||
}
|
||||
switch (queryData.value.selectKey) {
|
||||
case 0:
|
||||
query_data['GoodsName'] = queryData.value.word
|
||||
break
|
||||
case 1:
|
||||
query_data['UserName'] = queryData.value.word
|
||||
break
|
||||
case 2:
|
||||
query_data['Phone'] = queryData.value.word
|
||||
break
|
||||
case 3:
|
||||
query_data['Oid'] = queryData.value.word
|
||||
break
|
||||
}
|
||||
const res = await api.getOrder({
|
||||
pageNum: pagination.value.page,
|
||||
pageSize: pagination.value.pageSize,
|
||||
...query_data,
|
||||
})
|
||||
console.log(res)
|
||||
data.value = res.data.data || []
|
||||
pagination.value.itemCount = res.data.total
|
||||
cardData.value.total = res.data.number
|
||||
cardData.value.service = res.data.commission
|
||||
cardData.value.count = res.data.total
|
||||
} catch (error) {
|
||||
$message.error(error.msg)
|
||||
throw error
|
||||
}
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
const clear = () => {
|
||||
queryData.value = {
|
||||
status: '',
|
||||
time: null,
|
||||
word: '',
|
||||
selectKey: null,
|
||||
}
|
||||
getList()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
|
||||
5
src/views/order/index1/api.js
Normal file
@@ -0,0 +1,5 @@
|
||||
import { request } from '@/utils'
|
||||
|
||||
export default {
|
||||
getOrder: (data) => request.post('/order', data),
|
||||
}
|
||||
282
src/views/order/index1/index.vue
Normal file
@@ -0,0 +1,282 @@
|
||||
<template>
|
||||
<CommonPage show-footer :title="$route.title">
|
||||
<n-row gutter="12">
|
||||
<n-col :span="24">
|
||||
<div flex>
|
||||
<n-card w-500>
|
||||
<n-statistic label="订单流水" tabular-nums>
|
||||
<n-number-animation :from="0" :to="cardData.total" />
|
||||
</n-statistic>
|
||||
</n-card>
|
||||
<n-card ml-10 w-500>
|
||||
<n-statistic label="订单数量" tabular-nums>
|
||||
<n-number-animation :from="0" :to="cardData.count" />
|
||||
</n-statistic>
|
||||
</n-card>
|
||||
</div>
|
||||
</n-col>
|
||||
<n-col :span="24" mt-10>
|
||||
<div>
|
||||
<span>订单状态:</span>
|
||||
<n-radio-group v-model:value="queryData.status">
|
||||
<n-radio-button
|
||||
v-for="song in songs"
|
||||
:key="song.value"
|
||||
:value="song.value"
|
||||
:label="song.label"
|
||||
/>
|
||||
</n-radio-group>
|
||||
</div>
|
||||
</n-col>
|
||||
<n-col :span="24">
|
||||
<div mt-10 flex items-center>
|
||||
<div w-100>关键字搜索:</div>
|
||||
<n-input-group>
|
||||
<n-select
|
||||
v-model:value="queryData.selectKey"
|
||||
:style="{ width: '7%' }"
|
||||
:options="selectOptions"
|
||||
placeholder="请选择"
|
||||
/>
|
||||
<n-input v-model:value="queryData.word" :style="{ width: '20%' }" />
|
||||
</n-input-group>
|
||||
</div>
|
||||
</n-col>
|
||||
<n-col :span="10">
|
||||
<div mt-10 flex items-center>
|
||||
<span w-100>订单时间:</span>
|
||||
<n-date-picker
|
||||
v-model:formatted-value="queryData.time"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
type="datetimerange"
|
||||
clearable
|
||||
/>
|
||||
</div>
|
||||
</n-col>
|
||||
<n-col :span="24">
|
||||
<div mt-10>
|
||||
<n-button type="primary" @click="getList">搜索</n-button>
|
||||
<n-button ml-10 @click="clear">重置</n-button>
|
||||
</div>
|
||||
</n-col>
|
||||
</n-row>
|
||||
<n-data-table
|
||||
class="mt-5"
|
||||
:loading="loading"
|
||||
:columns="columns"
|
||||
:data="data"
|
||||
:pagination="pagination"
|
||||
:bordered="false"
|
||||
remote
|
||||
/>
|
||||
</CommonPage>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import api from './api'
|
||||
import { NEllipsis } from 'naive-ui'
|
||||
|
||||
const loading = ref(false)
|
||||
|
||||
const queryData = ref({
|
||||
status: '',
|
||||
time: null,
|
||||
word: '',
|
||||
selectKey: null,
|
||||
})
|
||||
|
||||
const songs = ref([
|
||||
{
|
||||
value: 1,
|
||||
label: '待付款',
|
||||
},
|
||||
{
|
||||
value: 2,
|
||||
label: '待核销',
|
||||
},
|
||||
{
|
||||
value: 3,
|
||||
label: '已核销',
|
||||
},
|
||||
{
|
||||
value: 4,
|
||||
label: '已过期',
|
||||
},
|
||||
])
|
||||
|
||||
const selectOptions = ref([
|
||||
{
|
||||
value: 0,
|
||||
label: '商品名称',
|
||||
},
|
||||
{
|
||||
value: 1,
|
||||
label: '用户昵称',
|
||||
},
|
||||
{
|
||||
value: 2,
|
||||
label: '手机号',
|
||||
},
|
||||
{
|
||||
value: 3,
|
||||
label: '订单号',
|
||||
},
|
||||
])
|
||||
|
||||
const columns = ref([
|
||||
{
|
||||
title: '订单号',
|
||||
align: 'center',
|
||||
key: 'oid',
|
||||
},
|
||||
{
|
||||
title: '用户',
|
||||
align: 'center',
|
||||
key: 'user_name',
|
||||
},
|
||||
{
|
||||
title: '手机号',
|
||||
align: 'center',
|
||||
key: 'phone',
|
||||
},
|
||||
{
|
||||
title: '商品名称',
|
||||
align: 'center',
|
||||
slot: 'goods_name',
|
||||
render: (row) => {
|
||||
return h(
|
||||
NEllipsis,
|
||||
{
|
||||
style: 'max-width: 240px',
|
||||
},
|
||||
{
|
||||
default: () => row.goods_name,
|
||||
}
|
||||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '商品数量',
|
||||
align: 'center',
|
||||
key: 'count',
|
||||
},
|
||||
{
|
||||
title: '商品总价',
|
||||
align: 'center',
|
||||
key: 'number',
|
||||
},
|
||||
{
|
||||
title: '订单状态',
|
||||
align: 'center',
|
||||
slot: 'status',
|
||||
render(row) {
|
||||
switch (row.status) {
|
||||
case 0:
|
||||
return h('span', '待付款')
|
||||
case 1:
|
||||
return h('span', '待使用')
|
||||
case 2:
|
||||
return h('span', '已完成')
|
||||
case 3:
|
||||
return h('span', '已过期')
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '下单时间',
|
||||
align: 'center',
|
||||
key: 'add_time',
|
||||
},
|
||||
{
|
||||
title: '核销时间',
|
||||
align: 'center',
|
||||
key: 'cancel_time',
|
||||
},
|
||||
// {
|
||||
// title: '操作',
|
||||
// align: 'center',
|
||||
// slot: 'action',
|
||||
// render() {
|
||||
// // console.log(row)
|
||||
// },
|
||||
// },
|
||||
])
|
||||
|
||||
const data = ref([])
|
||||
|
||||
const cardData = ref({
|
||||
total: 0,
|
||||
service: 0,
|
||||
count: 0,
|
||||
})
|
||||
|
||||
const pagination = ref({
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
itemCount: 0,
|
||||
onChange: (page) => {
|
||||
pagination.value.page = page
|
||||
getList()
|
||||
},
|
||||
onUpdatePageSize: (pageSize) => {
|
||||
pagination.value.pageSize = pageSize
|
||||
pagination.value.page = 1
|
||||
getList()
|
||||
},
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
getList()
|
||||
})
|
||||
|
||||
const getList = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const query_data = {
|
||||
Status: queryData.value.status || '',
|
||||
StartTime: queryData.value.time === null ? '' : queryData.value.time[0] || '',
|
||||
EndTime: queryData.value.time === null ? '' : queryData.value.time[1] || '',
|
||||
}
|
||||
switch (queryData.value.selectKey) {
|
||||
case 0:
|
||||
query_data['GoodsName'] = queryData.value.word
|
||||
break
|
||||
case 1:
|
||||
query_data['UserName'] = queryData.value.word
|
||||
break
|
||||
case 2:
|
||||
query_data['Phone'] = queryData.value.word
|
||||
break
|
||||
case 3:
|
||||
query_data['Oid'] = queryData.value.word
|
||||
break
|
||||
}
|
||||
const res = await api.getOrder({
|
||||
pageNum: pagination.value.page,
|
||||
pageSize: pagination.value.pageSize,
|
||||
...query_data,
|
||||
})
|
||||
data.value = res.data.data || []
|
||||
pagination.value.itemCount = res.data.total
|
||||
cardData.value.total = res.data.number
|
||||
cardData.value.service = res.data.commission
|
||||
cardData.value.count = res.data.total
|
||||
} catch (error) {
|
||||
$message.error(error.msg)
|
||||
throw error
|
||||
}
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
const clear = () => {
|
||||
queryData.value = {
|
||||
status: '',
|
||||
time: null,
|
||||
word: '',
|
||||
selectKey: null,
|
||||
}
|
||||
getList()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
@@ -8,17 +8,28 @@ export default {
|
||||
meta: {
|
||||
title: '订单管理',
|
||||
icon: 'majesticons:compass-line',
|
||||
order: 1,
|
||||
// requireAuth: true,
|
||||
// role: ['1'],
|
||||
order: 10,
|
||||
},
|
||||
children: [
|
||||
{
|
||||
name: 'OrderList',
|
||||
path: 'order_list',
|
||||
name: 'gyList',
|
||||
path: 'gy_list',
|
||||
component: () => import('./index1/index.vue'),
|
||||
meta: {
|
||||
requireAuth: true,
|
||||
role: ['1'],
|
||||
title: '订单列表',
|
||||
icon: 'material-symbols:auto-awesome-outline-rounded',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'dhList',
|
||||
path: 'dh_list',
|
||||
component: () => import('./index/index.vue'),
|
||||
meta: {
|
||||
requireAuth: true,
|
||||
title: '订单列表',
|
||||
role: ['2'],
|
||||
icon: 'material-symbols:auto-awesome-outline-rounded',
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { request } from '@/utils'
|
||||
|
||||
export default {
|
||||
getList: (data) => request.post('/order', data),
|
||||
getList: (data) => request.post('/record', data),
|
||||
}
|
||||
|
||||
@@ -1,7 +1,58 @@
|
||||
<template>
|
||||
<!-- <div> -->
|
||||
<CommonPage show-footer :title="$route.title">
|
||||
<n-row gutter="12">
|
||||
<n-col :span="24">
|
||||
<div flex>
|
||||
<n-card w-500>
|
||||
<n-statistic label="订单流水(积分)" tabular-nums>
|
||||
<n-number-animation :from="0" :to="cardData.total" />
|
||||
</n-statistic>
|
||||
</n-card>
|
||||
<n-card ml-10 w-500>
|
||||
<n-statistic label="订单服务费(积分)" tabular-nums>
|
||||
<n-number-animation :from="0" :to="cardData.service" />
|
||||
</n-statistic>
|
||||
</n-card>
|
||||
<n-card ml-10 w-500>
|
||||
<n-statistic label="订单数量" tabular-nums>
|
||||
<n-number-animation :from="0" :to="cardData.count" />
|
||||
</n-statistic>
|
||||
</n-card>
|
||||
</div>
|
||||
</n-col>
|
||||
<n-col :span="8">
|
||||
<div mt-10 flex items-center>
|
||||
<span>积分渠道:</span>
|
||||
<n-radio-group v-model:value="queryData.type">
|
||||
<n-radio-button
|
||||
v-for="song in songs"
|
||||
:key="song.value"
|
||||
:value="song.value"
|
||||
:label="song.label"
|
||||
/>
|
||||
</n-radio-group>
|
||||
</div>
|
||||
</n-col>
|
||||
<n-col :span="24">
|
||||
<div mt-10 flex items-center>
|
||||
<span>条件筛选:</span>
|
||||
<n-date-picker
|
||||
v-model:formatted-value="queryData.time"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
type="datetimerange"
|
||||
clearable
|
||||
/>
|
||||
</div>
|
||||
</n-col>
|
||||
<n-col :span="24">
|
||||
<div mt-10>
|
||||
<n-button type="primary" @click="getList">搜索</n-button>
|
||||
<n-button ml-10 @click="clear">重置</n-button>
|
||||
</div>
|
||||
</n-col>
|
||||
</n-row>
|
||||
<n-data-table
|
||||
class="mt-10"
|
||||
:loading="loading"
|
||||
:columns="columns"
|
||||
:data="data"
|
||||
@@ -10,35 +61,48 @@
|
||||
remote
|
||||
/>
|
||||
</CommonPage>
|
||||
<!-- </div> -->
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import api from './api'
|
||||
import { NEllipsis } from 'naive-ui'
|
||||
|
||||
const loading = ref(false)
|
||||
const columns = ref([
|
||||
|
||||
const songs = ref([
|
||||
{
|
||||
title: 'ID',
|
||||
key: 'ID',
|
||||
align: 'center',
|
||||
label: '订单',
|
||||
value: 1,
|
||||
},
|
||||
{
|
||||
title: '商品名称',
|
||||
key: 'goods_name',
|
||||
align: 'center',
|
||||
label: '提现',
|
||||
value: 2,
|
||||
},
|
||||
{
|
||||
title: '用户名称',
|
||||
key: 'user_name',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '获取积分',
|
||||
key: 'number',
|
||||
align: 'center',
|
||||
label: '增加(含驳回)',
|
||||
value: 3,
|
||||
},
|
||||
])
|
||||
|
||||
const queryData = ref({
|
||||
type: 1,
|
||||
time: null,
|
||||
})
|
||||
|
||||
const cardData = ref({
|
||||
total: 0,
|
||||
service: 0,
|
||||
count: 0,
|
||||
})
|
||||
|
||||
// watch(
|
||||
// () => queryData.value.type,
|
||||
// () => {
|
||||
// getList()
|
||||
// }
|
||||
// )
|
||||
|
||||
const columns = ref([])
|
||||
const data = ref([])
|
||||
|
||||
const pagination = ref({
|
||||
@@ -63,18 +127,137 @@ onMounted(() => {
|
||||
const getList = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
switch (queryData.value.type) {
|
||||
case 1:
|
||||
columns.value = [
|
||||
{
|
||||
title: 'ID',
|
||||
key: 'ID',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '商品名称',
|
||||
align: 'center',
|
||||
slot: 'goods_name',
|
||||
render: (row) => {
|
||||
return h(
|
||||
NEllipsis,
|
||||
{
|
||||
style: 'max-width: 240px',
|
||||
},
|
||||
{
|
||||
default: () => row.goods_name,
|
||||
}
|
||||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '商品数量',
|
||||
key: 'count',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '用户名称',
|
||||
key: 'user_name',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '上次留存积分',
|
||||
key: 'balance',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '获取积分',
|
||||
key: 'number',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '服务费',
|
||||
key: 'commission',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '时间',
|
||||
key: 'record_time',
|
||||
align: 'center',
|
||||
},
|
||||
]
|
||||
break
|
||||
case 2:
|
||||
columns.value = [
|
||||
{
|
||||
title: '单号',
|
||||
key: 'oid',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '上次留存积分',
|
||||
key: 'balance',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '扣除积分',
|
||||
key: 'record_number',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '时间',
|
||||
key: 'record_time',
|
||||
align: 'center',
|
||||
},
|
||||
]
|
||||
break
|
||||
case 3:
|
||||
columns.value = [
|
||||
{
|
||||
title: '单号',
|
||||
key: 'oid',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '上次留存积分',
|
||||
key: 'balance',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '获取积分',
|
||||
key: 'record_number',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '时间',
|
||||
key: 'record_time',
|
||||
align: 'center',
|
||||
},
|
||||
]
|
||||
break
|
||||
}
|
||||
|
||||
const res = await api.getList({
|
||||
pageNum: pagination.value.page,
|
||||
pageSize: pagination.value.pageSize,
|
||||
Type: queryData.value.type,
|
||||
StartTime: queryData.value.time === null ? '' : queryData.value.time[0] || '',
|
||||
EndTime: queryData.value.time === null ? '' : queryData.value.time[1] || '',
|
||||
})
|
||||
console.log(res)
|
||||
data.value = res.data.data || []
|
||||
pagination.value.itemCount = res.data.total
|
||||
cardData.value.total = res.data.number
|
||||
cardData.value.service = res.data.commission
|
||||
cardData.value.count = res.data.total
|
||||
} catch (error) {
|
||||
$message.error(error.msg)
|
||||
}
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
const clear = () => {
|
||||
queryData.value = {
|
||||
type: 1,
|
||||
time: null,
|
||||
}
|
||||
getList()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
|
||||
@@ -6,30 +6,32 @@ export default {
|
||||
component: Layout,
|
||||
redirect: '/settlement_list',
|
||||
meta: {
|
||||
title: '积分管理',
|
||||
requireAuth: true,
|
||||
order: 1,
|
||||
icon: 'mdi:account-multiple',
|
||||
order: 10,
|
||||
role: ['2'],
|
||||
},
|
||||
children: [
|
||||
{
|
||||
name: 'Settlementlist',
|
||||
path: 'settlement_list',
|
||||
component: () => import('./index/index.vue'),
|
||||
name: 'Jflist',
|
||||
path: 'jf_list',
|
||||
component: () => import('./jf_list/index.vue'),
|
||||
meta: {
|
||||
title: '积分明细',
|
||||
icon: 'mdi:account-multiple',
|
||||
order: 10,
|
||||
},
|
||||
},
|
||||
// {
|
||||
// name: 'Jflist',
|
||||
// path: 'jf_list',
|
||||
// component: () => import('./jf_list/index.vue'),
|
||||
// meta: {
|
||||
// title: '积分列表',
|
||||
// icon: 'mdi:account-multiple',
|
||||
// order: 10,
|
||||
// },
|
||||
// },
|
||||
{
|
||||
name: 'Txlist',
|
||||
path: 'tx_list',
|
||||
component: () => import('./tx_list/index.vue'),
|
||||
meta: {
|
||||
title: '积分提现',
|
||||
icon: 'mdi:account-multiple',
|
||||
order: 10,
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
7
src/views/settlement/tx_list/api.js
Normal file
@@ -0,0 +1,7 @@
|
||||
import { request } from '@/utils'
|
||||
|
||||
export default {
|
||||
getList: (data) => request.post('/withdraw', data),
|
||||
// 申请提现
|
||||
apply: (data) => request.post('/withdraw/set', data),
|
||||
}
|
||||
194
src/views/settlement/tx_list/index.vue
Normal file
@@ -0,0 +1,194 @@
|
||||
<template>
|
||||
<!-- <div> -->
|
||||
<CommonPage show-footer :title="$route.title">
|
||||
<div w-1200 flex items-center justify-between>
|
||||
<n-card class="w-300">
|
||||
<n-statistic label="可提现积分">
|
||||
<n-number-animation
|
||||
ref="numberAnimationInstRef"
|
||||
:precision="2"
|
||||
:from="0"
|
||||
:to="userInfo.integral"
|
||||
/>
|
||||
</n-statistic>
|
||||
</n-card>
|
||||
<div w-100 text-center text-25>/</div>
|
||||
<n-card class="w-300">
|
||||
<n-statistic label="兑换比例">
|
||||
<n-number-animation ref="numberAnimationInstRef" :precision="2" :from="0" :to="100" />
|
||||
</n-statistic>
|
||||
</n-card>
|
||||
<div w-100 text-center text-25>=</div>
|
||||
<n-card class="w-300">
|
||||
<n-statistic label="CNY">
|
||||
<n-number-animation
|
||||
ref="numberAnimationInstRef"
|
||||
:precision="2"
|
||||
:from="0"
|
||||
:to="userInfo.integral / 100"
|
||||
/>
|
||||
</n-statistic>
|
||||
</n-card>
|
||||
<div ml-10 flex flex-col items-center justify-center>
|
||||
<n-input-number v-model:value="formData.integral" clearable placeholder="请输入提现积分" />
|
||||
<n-button mt-10 w-full type="primary" @click="ok">立即提现</n-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<n-data-table
|
||||
class="mt-10"
|
||||
:loading="loading"
|
||||
:columns="columns"
|
||||
:data="data"
|
||||
:pagination="pagination"
|
||||
:bordered="false"
|
||||
remote
|
||||
/>
|
||||
</CommonPage>
|
||||
<!-- </div> -->
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import api from './api'
|
||||
import comm from '@/api'
|
||||
import { NTag, NImage } from 'naive-ui'
|
||||
|
||||
const loading = ref(false)
|
||||
const columns = ref([
|
||||
{
|
||||
title: 'ID',
|
||||
key: 'ID',
|
||||
align: 'center',
|
||||
},
|
||||
|
||||
{
|
||||
title: '提现积分',
|
||||
key: 'integral',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '银行名称',
|
||||
key: 'bank',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '银行卡号',
|
||||
key: 'bank_card',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '账户名称',
|
||||
key: 'bank_name',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '法人',
|
||||
key: 'bank_user',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '提现状态',
|
||||
slot: 'status',
|
||||
align: 'center',
|
||||
render: (row) => {
|
||||
return h(
|
||||
NTag,
|
||||
{
|
||||
type: row.status === 1 ? 'success' : row.status === 2 ? 'error' : 'warning',
|
||||
},
|
||||
{
|
||||
default: () => (row.status === 1 ? '已审核' : row.status === 2 ? '已拒绝' : '待审核'),
|
||||
}
|
||||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '提现时间',
|
||||
slot: 'add_time',
|
||||
align: 'center',
|
||||
render: (row) => {
|
||||
return h(
|
||||
'span',
|
||||
{},
|
||||
{
|
||||
default: () => row.add_time,
|
||||
}
|
||||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '打款截图',
|
||||
slot: 'img',
|
||||
render: (row) => {
|
||||
return h(NImage, {
|
||||
src: row.status_img,
|
||||
width: '50',
|
||||
})
|
||||
},
|
||||
},
|
||||
])
|
||||
const data = ref([])
|
||||
|
||||
const formData = ref({
|
||||
integral: null,
|
||||
})
|
||||
|
||||
const pagination = ref({
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
itemCount: 0,
|
||||
onChange: (page) => {
|
||||
pagination.value.page = page
|
||||
getList()
|
||||
},
|
||||
onUpdatePageSize: (pageSize) => {
|
||||
pagination.value.pageSize = pageSize
|
||||
pagination.value.page = 1
|
||||
getList()
|
||||
},
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
getList()
|
||||
getData()
|
||||
})
|
||||
|
||||
const userInfo = ref({})
|
||||
|
||||
const getData = async () => {
|
||||
const res = await comm.getMerchantInfo()
|
||||
userInfo.value = res.data.data
|
||||
}
|
||||
|
||||
const getList = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await api.getList({
|
||||
pageNum: pagination.value.page,
|
||||
pageSize: pagination.value.pageSize,
|
||||
})
|
||||
data.value = res.data.data || []
|
||||
pagination.value.itemCount = res.data.total
|
||||
} catch (error) {
|
||||
$message.error(error.msg)
|
||||
}
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
const ok = async () => {
|
||||
// if (formData.value.integral < 1000) return $message.warning('提现积分不能小于10000')
|
||||
const res = await api.apply({
|
||||
number: formData.value.integral,
|
||||
})
|
||||
$message.success(res.msg)
|
||||
clear()
|
||||
}
|
||||
|
||||
const clear = () => {
|
||||
formData.value.integral = null
|
||||
getList()
|
||||
getData()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
15
src/views/sys/api.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import { request } from '@/utils'
|
||||
|
||||
export default {
|
||||
getList: (data) => request.post('/staff/list', data),
|
||||
// 查找用户
|
||||
findUser: (data) => request.post('/find/user', data),
|
||||
// 绑定核销人员
|
||||
bindUser: (data) => request.post('/staff/user/set', data),
|
||||
// 获取商家信息
|
||||
getMerchantInfo: () => request.post('/info'),
|
||||
// 更新商家信息
|
||||
updateMerchantInfo: (data) => request.post('/edit', data),
|
||||
// 取消核销人员
|
||||
delVerifyUser: (data) => request.post('/staff/user/delete', data),
|
||||
}
|
||||
237
src/views/sys/index/index.vue
Normal file
@@ -0,0 +1,237 @@
|
||||
<script setup>
|
||||
import api from '../api'
|
||||
import Upload from '@/components/Upload.vue'
|
||||
|
||||
onMounted(() => {
|
||||
getInfo()
|
||||
})
|
||||
|
||||
const infoData = ref({})
|
||||
|
||||
const model = ref({})
|
||||
|
||||
const formRef = ref(null)
|
||||
|
||||
const showModal = ref(false)
|
||||
|
||||
const rules = {
|
||||
name: {
|
||||
required: true,
|
||||
message: '请输入店铺名称',
|
||||
trigger: 'blur',
|
||||
},
|
||||
head_photo: {
|
||||
required: true,
|
||||
type: 'array',
|
||||
message: '请输入上传店铺封面图',
|
||||
trigger: 'blur',
|
||||
},
|
||||
bank: {
|
||||
required: true,
|
||||
message: '请输入银行名称',
|
||||
trigger: 'blur',
|
||||
},
|
||||
bank_card: {
|
||||
required: true,
|
||||
message: '请输入银行卡号',
|
||||
trigger: 'blur',
|
||||
},
|
||||
bank_name: {
|
||||
required: true,
|
||||
message: '请输入账户名称',
|
||||
trigger: 'blur',
|
||||
},
|
||||
bank_user: {
|
||||
required: true,
|
||||
message: '请输入法定代表人',
|
||||
trigger: 'blur',
|
||||
},
|
||||
img: {
|
||||
required: true,
|
||||
type: 'array',
|
||||
message: '请输入上传店铺轮播图',
|
||||
trigger: 'blur',
|
||||
},
|
||||
address: {
|
||||
required: true,
|
||||
message: '请输入店铺详细地址',
|
||||
trigger: 'blur',
|
||||
},
|
||||
lt: {
|
||||
required: true,
|
||||
message: '请查找店铺经纬度',
|
||||
},
|
||||
week: {
|
||||
required: true,
|
||||
type: 'array',
|
||||
message: '请选择营业日期',
|
||||
},
|
||||
week_start: {
|
||||
required: true,
|
||||
message: '请选择营业开始时间',
|
||||
},
|
||||
week_end: {
|
||||
required: true,
|
||||
message: '请选择营业结束时间',
|
||||
},
|
||||
mobile: {
|
||||
required: true,
|
||||
message: '请输入店铺手机号',
|
||||
},
|
||||
}
|
||||
|
||||
const days = ref([
|
||||
{ label: '周一', value: '1' },
|
||||
{ label: '周二', value: '2' },
|
||||
{ label: '周三', value: '3' },
|
||||
{ label: '周四', value: '4' },
|
||||
{ label: '周五', value: '5' },
|
||||
{ label: '周六', value: '6' },
|
||||
{ label: '周日', value: '7' },
|
||||
])
|
||||
|
||||
const getInfo = async () => {
|
||||
const res = await api.getMerchantInfo()
|
||||
infoData.value = res.data.data
|
||||
console.log((!res.data.data.week_start && 1) || '00:00:00')
|
||||
model.value = {
|
||||
...res.data.data,
|
||||
head_photo: [{ url: res.data.data.head_photo, status: 'finished', id: 1 }],
|
||||
img: res.data.data.img
|
||||
.split(',')
|
||||
.map((item, index) => ({ url: item, status: 'finished', id: index })),
|
||||
lt: `${res.data.data.lat},${res.data.data.lon}`,
|
||||
week: res.data.data.week.length === 0 ? [] : res.data.data.week.split(','),
|
||||
week_start: res.data.data.week_start.length === 0 ? '00:00:00' : res.data.data.week_start,
|
||||
week_end: res.data.data.week_end.length === 0 ? '00:00:00' : res.data.data.week_end,
|
||||
}
|
||||
}
|
||||
|
||||
// 选中位置触发该函数
|
||||
window.addEventListener('message', (res) => {
|
||||
model.value.lt = `${res.data?.latlng?.lat},${res.data?.latlng?.lng}`
|
||||
model.value.lat = res.data?.latlng?.lat
|
||||
model.value.lon = res.data.latlng?.lng
|
||||
showModal.value = false
|
||||
})
|
||||
|
||||
const submit = () => {
|
||||
formRef.value?.validate(async (errors) => {
|
||||
if (!errors) {
|
||||
const data = {
|
||||
...model.value,
|
||||
head_photo: model.value.head_photo[0].url,
|
||||
img: model.value.img.map((item) => item.url).join(','),
|
||||
lat: model.value.lat.toString(),
|
||||
lon: model.value.lon.toString(),
|
||||
week: model.value.week.join(','),
|
||||
}
|
||||
delete data.lt
|
||||
const res = await api.updateMerchantInfo(data)
|
||||
$message.success(res.msg)
|
||||
getInfo()
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<CommonPage show-footer :title="$route.title">
|
||||
<n-tabs type="line" animated>
|
||||
<n-tab-pane name="1" tab="基本信息">
|
||||
<div>商户名称: {{ infoData.name }}</div>
|
||||
<div>负责人手机号码: {{ infoData.phone }}</div>
|
||||
<div>商户类型: {{ infoData.bType === 1 ? '供应商' : '兑换商' }}</div>
|
||||
<!-- <div>经营类目: {{ infoData.scope }}</div> -->
|
||||
<div>入驻时间: {{ infoData.add_time }}</div>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="2" tab="店铺信息">
|
||||
<!-- {{ model }} -->
|
||||
<n-form ref="formRef" :model="model" :rules="rules" label-placement="left">
|
||||
<n-grid :cols="24" :x-gap="24">
|
||||
<n-form-item-gi :span="24" label="店铺封面图:" path="head_photo">
|
||||
<Upload v-model:list="model.head_photo" :max="1" />
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi :span="24" label="店铺轮播图:" path="img">
|
||||
<Upload v-model:list="model.img" :max="5" />
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi :span="15" label="店铺号码:" path="mobile">
|
||||
<n-input v-model:value="model.mobile" placeholder="请输入店铺号码" />
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi :span="15" label="法定代表人:" path="bank_user">
|
||||
<n-input v-model:value="model.bank_user" placeholder="请输入法定代表人" />
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi :span="15" label="账户名称:" path="bank_name">
|
||||
<n-input v-model:value="model.bank_name" placeholder="请输入账户名称" />
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi :span="15" label="开户银行:" path="bank">
|
||||
<n-input v-model:value="model.bank" placeholder="请输入开户银行" />
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi :span="15" label="银行卡号:" path="bank_card">
|
||||
<n-input v-model:value="model.bank_card" placeholder="请输入银行卡号" />
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi :span="15" label="营业日期:" path="week">
|
||||
<n-select v-model:value="model.week" multiple :options="days" />
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi :span="15" label="营业开始时间:" path="week_start">
|
||||
<n-time-picker
|
||||
v-model:formatted-value="model.week_start"
|
||||
value-format="HH:mm:ss"
|
||||
clearable
|
||||
/>
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi :span="15" label="营业结束时间:" path="week_end">
|
||||
<n-time-picker
|
||||
v-model:formatted-value="model.week_end"
|
||||
value-format="HH:mm:ss"
|
||||
clearable
|
||||
/>
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi :span="15" label="店铺名称:" path="name">
|
||||
<n-input v-model:value="model.name" placeholder="请输入店铺名称" />
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi :span="15" label="店铺详细地址:" path="address">
|
||||
<n-input v-model:value="model.address" placeholder="请输入店铺详细地址" />
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi :span="15" label="店铺经纬度:" path="lt">
|
||||
<n-input-group>
|
||||
<n-input
|
||||
v-model:value="model.lt"
|
||||
placeholder="请查找店铺经纬度"
|
||||
:style="{ width: '100%' }"
|
||||
/>
|
||||
<n-button type="primary" @click="showModal = true">查找位置</n-button>
|
||||
</n-input-group>
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi :span="15">
|
||||
<div class="m-auto">
|
||||
<n-button type="primary" w-100 @click="submit">提交</n-button>
|
||||
</div>
|
||||
</n-form-item-gi>
|
||||
</n-grid>
|
||||
</n-form>
|
||||
</n-tab-pane>
|
||||
<!-- <n-tab-pane name="3" tab="功能信息">开发中</n-tab-pane> -->
|
||||
</n-tabs>
|
||||
<!-- h5地图 -->
|
||||
<n-modal v-if="showModal" v-model:show="showModal">
|
||||
<n-card
|
||||
style="width: 600px; height: 600px"
|
||||
title="查找地图位置"
|
||||
:bordered="false"
|
||||
size="huge"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
>
|
||||
<iframe
|
||||
src="https://apis.map.qq.com/tools/locpicker?type=1&key=S3GBZ-WR26O-IXNW2-SXBOD-LZXV6-WAFNO&referer=myapp"
|
||||
width="100%"
|
||||
height="100%"
|
||||
frameborder="0"
|
||||
></iframe>
|
||||
</n-card>
|
||||
</n-modal>
|
||||
</CommonPage>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
35
src/views/sys/route.js
Normal file
@@ -0,0 +1,35 @@
|
||||
const Layout = () => import('@/layout/index.vue')
|
||||
|
||||
export default {
|
||||
name: '商户设置',
|
||||
path: '/sys',
|
||||
component: Layout,
|
||||
redirect: '/sys_info',
|
||||
meta: {
|
||||
title: '商户设置',
|
||||
icon: 'mdi:account-multiple',
|
||||
order: 10,
|
||||
},
|
||||
children: [
|
||||
{
|
||||
name: 'SysInfo',
|
||||
path: 'sys_info',
|
||||
component: () => import('./index/index.vue'),
|
||||
meta: {
|
||||
title: '商户信息',
|
||||
icon: 'mdi:account-multiple',
|
||||
order: 10,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'SysVerify',
|
||||
path: 'sys_verify',
|
||||
component: () => import('./verify/index.vue'),
|
||||
meta: {
|
||||
title: '核销人员',
|
||||
icon: 'mdi:account-multiple',
|
||||
order: 10,
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
242
src/views/sys/verify/index.vue
Normal file
@@ -0,0 +1,242 @@
|
||||
<script setup>
|
||||
import api from '../api.js'
|
||||
import { NAvatar, NButton, NPopconfirm } from 'naive-ui'
|
||||
|
||||
const loading = ref(false)
|
||||
|
||||
const columns = ref([
|
||||
{
|
||||
title: '头像',
|
||||
slot: 'avatarUrl',
|
||||
align: 'center',
|
||||
render: (row) => {
|
||||
return h(NAvatar, { src: row.avatarUrl, round: true, size: 50 })
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '昵称',
|
||||
key: 'nickName',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '手机号',
|
||||
key: 'phone',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
slot: 'action',
|
||||
align: 'center',
|
||||
render: (row) => {
|
||||
console.log(row)
|
||||
return [
|
||||
h(
|
||||
NButton,
|
||||
{
|
||||
text: true,
|
||||
size: 'small',
|
||||
type: 'primary',
|
||||
onClick: () => {
|
||||
addUser(2, row)
|
||||
},
|
||||
},
|
||||
{
|
||||
default: () => '编辑',
|
||||
}
|
||||
),
|
||||
h(
|
||||
NPopconfirm,
|
||||
{
|
||||
onPositiveClick: () => {
|
||||
delVerifyUser(row)
|
||||
},
|
||||
},
|
||||
{
|
||||
default: () => '删除无法撤销,请谨慎!',
|
||||
trigger: () =>
|
||||
h(
|
||||
NButton,
|
||||
{
|
||||
text: true,
|
||||
class: 'ml-10',
|
||||
size: 'small',
|
||||
type: 'error',
|
||||
},
|
||||
{
|
||||
default: () => '删除',
|
||||
}
|
||||
),
|
||||
}
|
||||
),
|
||||
]
|
||||
},
|
||||
},
|
||||
])
|
||||
|
||||
const data = ref([])
|
||||
|
||||
const showModal = ref(false)
|
||||
|
||||
const showModalTitle = ref('')
|
||||
|
||||
const pagination = ref({
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
itemCount: 0,
|
||||
onChange: (page) => {
|
||||
pagination.value.page = page
|
||||
get_list()
|
||||
},
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
get_list()
|
||||
})
|
||||
|
||||
const get_list = async () => {
|
||||
loading.value = true
|
||||
const res = await api.getList({
|
||||
PageNum: pagination.value.page,
|
||||
PageSize: pagination.value.pageSize,
|
||||
})
|
||||
data.value = res.data.data || []
|
||||
pagination.value.itemCount = res.data.total
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
const addUser = (type, row = {}) => {
|
||||
showModalTitle.value = type === 1 ? '添加核销人员' : '编辑核销人员'
|
||||
if (type === 2) {
|
||||
model.value = {
|
||||
inputValue: row.phone,
|
||||
id: row.uid,
|
||||
url: row.avatarUrl,
|
||||
name: row.nickName,
|
||||
}
|
||||
}
|
||||
showModal.value = true
|
||||
}
|
||||
|
||||
const formRef = ref(null)
|
||||
|
||||
const model = ref({
|
||||
inputValue: '',
|
||||
url: '',
|
||||
id: null,
|
||||
name: '',
|
||||
})
|
||||
|
||||
const search = async () => {
|
||||
const res = await api.findUser({
|
||||
phone: model.value.inputValue,
|
||||
})
|
||||
model.value = {
|
||||
...model.value,
|
||||
id: res.data.data.uid,
|
||||
url: res.data.data.avatarUrl,
|
||||
name: res.data.data.nickName,
|
||||
}
|
||||
}
|
||||
|
||||
const submit = async () => {
|
||||
if (!model.value.id) return $message.error('请绑定核销人员')
|
||||
const res = await api.bindUser({
|
||||
uid: model.value.id,
|
||||
})
|
||||
$message.success(res.msg)
|
||||
clear()
|
||||
}
|
||||
|
||||
const clear = () => {
|
||||
model.value = {
|
||||
inputValue: '',
|
||||
url: '',
|
||||
id: null,
|
||||
name: '',
|
||||
}
|
||||
showModal.value = false
|
||||
get_list()
|
||||
}
|
||||
|
||||
const delVerifyUser = async (row) => {
|
||||
const res = await api.delVerifyUser({
|
||||
uid: row.uid,
|
||||
})
|
||||
$message.success(res.msg)
|
||||
get_list()
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<CommonPage show-footer :title="$route.title">
|
||||
<n-button type="primary" @click="addUser(1)">添加核销人员</n-button>
|
||||
<n-data-table
|
||||
class="mt-10"
|
||||
:loading="loading"
|
||||
:columns="columns"
|
||||
:data="data"
|
||||
:pagination="pagination"
|
||||
:bordered="false"
|
||||
remote
|
||||
/>
|
||||
<!-- 添加对话框 -->
|
||||
<n-modal v-model:show="showModal">
|
||||
<n-card
|
||||
style="width: 600px"
|
||||
:title="showModalTitle"
|
||||
:bordered="false"
|
||||
size="huge"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
>
|
||||
<n-form ref="formRef" :model="model" label-placement="left">
|
||||
<n-grid :cols="1" :x-gap="24">
|
||||
<n-form-item-gi class="flex items-center" label="查找用户" :span="20">
|
||||
<n-input-group>
|
||||
<n-input
|
||||
v-model:value="model.inputValue"
|
||||
placeholder="请输入用户手机号"
|
||||
:style="{ width: '90%' }"
|
||||
/>
|
||||
<n-button type="primary" ghost @click="search">搜索</n-button>
|
||||
</n-input-group>
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi class="flex items-center" label="绑定用户" :span="12">
|
||||
<div v-if="model.url !== '' && model.id !== null" class="text-center">
|
||||
<img class="h-100 w-100 border rounded-5" :src="model.url || ''" />
|
||||
<div>{{ model.name }}</div>
|
||||
</div>
|
||||
|
||||
<div v-else class="checkBox">+</div>
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi>
|
||||
<div m-auto>
|
||||
<n-button type="primary" @click="submit">提交</n-button>
|
||||
<n-button ml-10 @click="clear">取消</n-button>
|
||||
</div>
|
||||
</n-form-item-gi>
|
||||
</n-grid>
|
||||
</n-form>
|
||||
</n-card>
|
||||
</n-modal>
|
||||
</CommonPage>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.checkBox {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background-color: rgb(250, 250, 252);
|
||||
border: 1px dashed rgb(224, 224, 230);
|
||||
border-radius: 3px;
|
||||
text-align: center;
|
||||
line-height: 100px;
|
||||
font-size: 30px;
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
border: 1px dashed #18a058;
|
||||
transition: 1s all;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -22,13 +22,18 @@ const columns = ref([
|
||||
align: 'center',
|
||||
key: 'ID',
|
||||
},
|
||||
{
|
||||
title: '昵称',
|
||||
align: 'center',
|
||||
key: 'nickName',
|
||||
},
|
||||
{
|
||||
title: '头像',
|
||||
align: 'center',
|
||||
slot: 'avatar',
|
||||
slot: 'avatarUrl',
|
||||
render(row) {
|
||||
return h('img', {
|
||||
src: row.avatar,
|
||||
src: row.avatarUrl,
|
||||
style: {
|
||||
width: '30px',
|
||||
height: '30px',
|
||||
@@ -52,14 +57,14 @@ const columns = ref([
|
||||
align: 'center',
|
||||
key: 'pulse',
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
align: 'center',
|
||||
slot: 'action',
|
||||
render(row) {
|
||||
console.log(row)
|
||||
},
|
||||
},
|
||||
// {
|
||||
// title: '操作',
|
||||
// align: 'center',
|
||||
// slot: 'action',
|
||||
// render(row) {
|
||||
// console.log(row)
|
||||
// },
|
||||
// },
|
||||
])
|
||||
|
||||
const data = ref([])
|
||||
|
||||
@@ -5,6 +5,11 @@ export default {
|
||||
path: '/user',
|
||||
component: Layout,
|
||||
redirect: '/user_list',
|
||||
meta: {
|
||||
title: '用户管理',
|
||||
icon: 'mdi:account-multiple',
|
||||
order: 10,
|
||||
},
|
||||
children: [
|
||||
{
|
||||
name: 'Userlist',
|
||||
|
||||
@@ -8,51 +8,16 @@
|
||||
<p text-16>Hello, {{ userStore.name }}</p>
|
||||
<p mt-5 text-12 op-60>今天又是元气满满的一天</p>
|
||||
</div>
|
||||
<!-- <div ml-auto flex items-center>
|
||||
<n-statistic label="待办" :value="4">
|
||||
<template #suffix>/ 10</template>
|
||||
</n-statistic>
|
||||
<n-statistic label="Stars" ml-80 w-100>
|
||||
<a href="https://github.com/zclzone/vue-naive-admin">
|
||||
<img alt="stars" src="https://badgen.net/github/stars/zclzone/vue-naive-admin" />
|
||||
</a>
|
||||
</n-statistic>
|
||||
<n-statistic label="Forks" ml-80 w-100>
|
||||
<a href="https://github.com/zclzone/vue-naive-admin">
|
||||
<img alt="forks" src="https://badgen.net/github/forks/zclzone/vue-naive-admin" />
|
||||
</a>
|
||||
</n-statistic>
|
||||
</div> -->
|
||||
</div>
|
||||
</n-card>
|
||||
|
||||
<!-- <n-card title="项目" size="small" :segmented="true" mt-15 rounded-10>
|
||||
<template #header-extra>
|
||||
<n-button text type="primary">更多</n-button>
|
||||
</template>
|
||||
<div flex flex-wrap justify-between>
|
||||
<n-card
|
||||
v-for="i in 10"
|
||||
:key="i"
|
||||
class="mb-10 mt-10 w-300 flex-shrink-0 cursor-pointer"
|
||||
hover:card-shadow
|
||||
title="Vue Naive Admin"
|
||||
size="small"
|
||||
>
|
||||
<p op-60>一个基于 Vue3.0、Vite、Naive UI 的轻量级后台管理模板</p>
|
||||
</n-card>
|
||||
<div h-0 w-300></div>
|
||||
<div h-0 w-300></div>
|
||||
<div h-0 w-300></div>
|
||||
<div h-0 w-300></div>
|
||||
</div>
|
||||
</n-card> -->
|
||||
<!-- <Map /> -->
|
||||
</div>
|
||||
</AppPage>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useUserStore } from '@/store'
|
||||
// import Map from '@/components/Map.vue'
|
||||
|
||||
const userStore = useUserStore()
|
||||
</script>
|
||||
|
||||
@@ -24,6 +24,7 @@ export default defineConfig(({ command, mode }) => {
|
||||
plugins: createVitePlugins(viteEnv, isBuild),
|
||||
server: {
|
||||
host: '0.0.0.0',
|
||||
https: false,
|
||||
port: VITE_PORT,
|
||||
open: false,
|
||||
proxy: VITE_USE_PROXY
|
||||
|
||||