feat:main css

This commit is contained in:
wangzenghua 2025-02-10 05:54:41 +00:00
parent 567575561a
commit c9829c6a5c
24 changed files with 1142 additions and 313 deletions

View File

@ -2,10 +2,13 @@
VITE_PORT = 9000
VITE_APP_NAME = 'daimp-front-main'
VITE_APP_TITLE = '数字农业产业管理平台'
VITE_APP_BASE_API = "https://mock.mengxuegu.com/mock/664ef7fee45d2156fa209ee4/api-qiankun"
VITE_APP_BASE_URL = 'http://192.168.18.158:9080'
VITE_APP_SUB_VUE = '//localhost:9526/sub-operation-service/'
VITE_APP_SUB_ADMIN = '//localhost:9527/sub-admin/'
VITE_APP_SUB_GAS = '//localhost:9528/suv-government-affairs-service/'
# 接口
VITE_APP_BASE_API = '/apis'
VITE_APP_BASE_URL = 'http://192.168.18.99:8080'
VITE_APP_UPLOAD_API = '/uploadApis'
VITE_APP_UPLOAD_URL = 'http://192.168.18.99:9300'
VITE_APP_SYSTEM_API = '/systemApis'
VITE_APP_SYSTEM_URL = 'http://192.168.18.99:99/stage-api'

View File

@ -0,0 +1,101 @@
<template>
<el-dialog
v-model="state.visible"
draggable
title="文件导入"
width="50%"
top="10px"
:close-on-click-modal="false"
:close-on-press-escape="false"
@close="onClose"
>
<div class="import-tips">
<p>{{ tips }}</p>
<el-button v-if="templateUrl" type="primary" icon="download" text @click="emit('on-download', templateUrl)">下载模板</el-button>
</div>
<el-upload ref="uploadRef" drag action="#" :show-file-list="true" accept=".xlsx,.xls" :limit="1" :http-request="onUploadExcel">
<el-icon class="el-icon--upload"><upload-filled /></el-icon>
<div class="el-upload__text">将文件放在此处或单击上传</div>
<template #tip>
<div class="el-upload__tip">excel文件大小小于500kb</div>
</template>
</el-upload>
<template #footer>
<el-button type="primary" @click="onConfirm"> 确定导入</el-button>
<el-button @click="onClose"> 取消</el-button>
</template>
</el-dialog>
</template>
<script setup name="custom-import-excel">
import { reactive, ref, shallowRef } from 'vue';
import { isEmpty } from '@/utils';
const props = defineProps({
tips: {
type: String,
default: '提示:导入前请先下载模板填写信息,然后再导入!',
},
templateUrl: {
type: String,
default: '',
},
// options: {
// type: Object,
// default: () => {
// return {
// tips: '',
// };
// },
// },
});
const emit = defineEmits(['on-confirm', 'on-close', 'on-download']);
const uploadRef = ref(null);
const formDate = shallowRef(null);
const state = reactive({
visible: false,
loading: false,
});
const onUploadExcel = ({ file }) => {
if (isEmpty(file.name)) return;
formDate.value = new FormData();
formDate.value.append('file', file);
};
const onConfirm = () => {
emit('on-confirm', formDate.value);
};
const onClose = () => {
uploadRef?.value && uploadRef.value.clearFiles();
state.visible = false;
};
defineExpose({
show: () => {
formDate.value = null;
state.visible = true;
},
hide: () => {
onClose();
},
clear: () => {
uploadRef?.value && uploadRef.value.clearFiles();
},
});
</script>
<style lang="scss" scoped>
.import {
&-tips {
@include flex-row();
align-items: center;
margin-bottom: 20px;
font-size: 14px;
color: #979797;
p {
flex: 3;
}
}
}
</style>

View File

@ -1,6 +1,7 @@
import SvgIcon from './svg-icon';
import CustomTableOperate from './custom-table-operate';
import CustomImportExcel from './custom-import-excel';
import CustomRichEditor from './custom-rich-editor';
import CustomEchartBar from './custom-echart-bar';
export { SvgIcon, CustomTableOperate, CustomEchartBar, CustomRichEditor };
export { SvgIcon, CustomTableOperate, CustomImportExcel, CustomEchartBar, CustomRichEditor };

View File

@ -3,34 +3,34 @@ import actions from './actions';
const { VITE_APP_SUB_VUE, VITE_APP_SUB_ADMIN, VITE_APP_SUB_GAS } = import.meta.env;
export const leftApps = [
{
name: 'sub-operation-service',
entry: VITE_APP_SUB_VUE,
activeRule: '/sub-operation-service/',
title: '运营服务',
icon: 'platform/icon-home.png',
},
{
name: 'sub-admin',
entry: VITE_APP_SUB_ADMIN,
activeRule: '/sub-admin/',
title: '管理后台',
icon: 'platform/icon-admin.png',
},
{
name: 'sub-app',
entry: VITE_APP_SUB_ADMIN,
activeRule: '/sub-app/',
title: 'APP',
icon: 'platform/icon-app.png',
},
{
name: 'sub-screen',
entry: VITE_APP_SUB_ADMIN,
activeRule: '/sub-screen/',
title: '数据大屏',
icon: 'platform/icon-screen.png',
},
// {
// name: 'sub-operation-service',
// entry: VITE_APP_SUB_VUE,
// activeRule: '/sub-operation-service/',
// title: '运营服务',
// icon: 'platform/icon-home.png',
// },
// {
// name: 'sub-admin',
// entry: VITE_APP_SUB_ADMIN,
// activeRule: '/sub-admin/',
// title: '管理后台',
// icon: 'platform/icon-admin.png',
// },
// {
// name: 'sub-app',
// entry: VITE_APP_SUB_ADMIN,
// activeRule: '/sub-app/',
// title: 'APP',
// icon: 'platform/icon-app.png',
// },
// {
// name: 'sub-screen',
// entry: VITE_APP_SUB_ADMIN,
// activeRule: '/sub-screen/',
// title: '数据大屏',
// icon: 'platform/icon-screen.png',
// },
];
export const rightApps = [
@ -41,27 +41,27 @@ export const rightApps = [
title: '政务服务',
icon: 'platform/icon-home.png',
},
{
name: 'sub-government-admin',
entry: VITE_APP_SUB_ADMIN,
activeRule: '/sub-government-admin/',
title: '管理后台',
icon: 'platform/icon-admin.png',
},
{
name: 'sub-government-app',
entry: VITE_APP_SUB_ADMIN,
activeRule: '/sub-government-app/',
title: 'APP',
icon: 'platform/icon-app.png',
},
{
name: 'sub-government-screen',
entry: VITE_APP_SUB_ADMIN,
activeRule: '/sub-government-screen/',
title: '数据大屏',
icon: 'platform/icon-screen.png',
},
// {
// name: 'sub-government-admin',
// entry: VITE_APP_SUB_ADMIN,
// activeRule: '/sub-government-admin/',
// title: '管理后台',
// icon: 'platform/icon-admin.png',
// },
// {
// name: 'sub-government-app',
// entry: VITE_APP_SUB_ADMIN,
// activeRule: '/sub-government-app/',
// title: 'APP',
// icon: 'platform/icon-app.png',
// },
// {
// name: 'sub-government-screen',
// entry: VITE_APP_SUB_ADMIN,
// activeRule: '/sub-government-screen/',
// title: '数据大屏',
// icon: 'platform/icon-screen.png',
// },
];
export const microApps = [...leftApps, ...rightApps];

View File

@ -1,4 +1,4 @@
@use "sass:list";
@use 'sass:list';
.flex {
&-row {
@ -28,67 +28,3 @@
.text-right {
text-align: right;
}
.custom {
&-page {
display: flex;
justify-content: center;
.el-pagination {
font-size: 24px;
}
.el-pagination .btn-next.is-active,
.el-pagination .btn-prev.is-active,
.el-pagination .el-pager li.is-active {
color: $color-primary !important;
}
.el-pagination .btn-next,
.el-pagination .btn-prev,
.el-pagination .el-pager li {
margin: 0 12px !important;
font-size: 24px;
color: #999;
}
.el-pagination .btn-next,
.el-pagination .btn-prev {
// border: 1px dashed #ddd;
&:hover {
color: #000 !important;
}
}
.el-pagination .btn-next .el-icon,
.el-pagination .btn-prev .el-icon {
font-size: 32px !important;
font-weight: 500 !important;
}
.el-pagination .el-pager li {
&:hover {
font-weight: 500;
color: $color-primary !important;
}
}
&-jumper {
margin-left: 40px;
display: flex;
flex-direction: row;
align-items: center;
span {
font-size: 24px;
color: #999;
}
.el-input {
width: 50px !important;
margin: 0 20px;
font-size: 24px;
}
}
}
}

View File

@ -2,16 +2,12 @@
* @Descripttion:
* @Author: zenghua.wang
* @Date: 2022-02-23 21:12:37
* @LastEditors: wzh 1048523306@qq.com
* @LastEditTime: 2024-12-17 11:55:31
* @LastEditors: zenghua.wang
* @LastEditTime: 2025-02-07 14:38:05
*/
import lodash from 'lodash';
import dayjs from 'dayjs';
import { cloneDeep } from 'lodash';
import { Base64 } from 'js-base64';
import JsZip from 'jszip';
import JsZipUtils from 'jszip-utils';
import { saveAs } from 'file-saver';
/**
* @Title 防抖指在一定时间内多次触发同一个事件只执行最后一次操作
@ -68,7 +64,7 @@ export const isEmpty = (val) => {
* @returns
*/
export const deepClone = (obj = {}) => {
return cloneDeep(obj);
return lodash.cloneDeep(obj);
};
/**
* @Title 将number转换为px
@ -77,7 +73,21 @@ export const deepClone = (obj = {}) => {
*/
export const setPx = (val) => {
if (isEmpty(val)) return '';
return typeof val === 'number' ? `${val}px` : val;
val = val + '';
if (val.indexOf('%') === -1) {
val = val + 'px';
}
return val;
};
/**
* @Tilte 设置属性默认值
* @param {*} options
* @param {*} prop
* @param {*} defaultVal
* @returns
*/
export const setDefaultOption = (options, prop, defaultVal) => {
return options[prop] === undefined ? defaultVal : options.prop;
};
/**
* @Title 设置字典值
@ -261,14 +271,6 @@ export const getUrlQuery = (name) => {
const usp = new URLSearchParams(search);
return usp.get(name);
};
/**
* @Title 将字符串url参数转换为Object
* @param {*} url
* @returns
*/
export const param2Obj = (url) => {
return (url) => Object.fromEntries(new URLSearchParams(url));
};
/**
* @Title 将Object参数转换为字符串
* @param {*} json
@ -292,88 +294,40 @@ export const getAssetsFile = (url) => {
return new URL(`../assets/images/${url}`, import.meta.url);
};
/**
* 文件下载
* @param {*} url
* @param {*} fileName
* @returns
* @Title: a链接方式文件下载
* @param {void} content:
* @param {void} fileName:
* @return {void}
*/
export const dowloadFile = async (options = { url: '', files: null, fileName: '' }) => {
const { url, files, fileName } = options;
const chunkSize = 1 * 1024 * 1024;
const jszip = new JsZip();
function chunkFile(file, chunkSize) {
let chunks = [];
let fileSize = file.size;
let currentPos = 0;
while (currentPos < fileSize) {
let endPos = currentPos + chunkSize;
if (endPos > fileSize) {
endPos = fileSize;
}
chunks.push(file.slice(currentPos, endPos));
currentPos = endPos;
}
return chunks;
export const downloadLink = (url, fileName) => {
const elink = document.createElement('a');
elink.download = fileName;
elink.style.display = 'none';
elink.href = url;
elink.target = '_blank';
elink.click();
elink.remove();
};
/**
* @Title: 下载文件
* @param {void} content:
* @param {void} fileName:
* @return {void}
*/
export const downloadFile = (content, fileName) => {
const blob = new Blob([content]);
if ('download' in document.createElement('a')) {
const elink = document.createElement('a');
elink.download = fileName;
elink.style.display = 'none';
elink.href = URL.createObjectURL(blob);
document.body.appendChild(elink);
elink.click();
URL.revokeObjectURL(elink.href);
document.body.removeChild(elink);
} else {
navigator.msSaveBlob(blob, fileName);
}
function dowloadLink(content, fileName) {
const blob = new Blob([content]);
if ('download' in document.createElement('a')) {
const elink = document.createElement('a');
elink.download = fileName;
elink.style.display = 'none';
elink.href = URL.createObjectURL(blob);
document.body.appendChild(elink);
elink.click();
URL.revokeObjectURL(elink.href);
document.body.removeChild(elink);
} else {
navigator.msSaveBlob(blob, fileName);
}
}
return new Promise((resolve, reject) => {
if (!isEmpty(options?.url)) {
JsZipUtils.getBinaryContent(url, (err, file) => {
if (err) {
return reject(err);
}
jszip
.loadAsync(file)
.then((zip) => {
return zip.generateAsync({ type: 'blob' });
})
.then((blob) => {
saveAs(blob, `${fileName}.zip`);
});
});
} else {
// if (files.type === 'binary/octet-stream') {
// dowloadLink(files, fileName);
// return;
// }
let chunks = null;
if (files.size > chunkSize) {
chunks = chunkFile(files, chunkSize);
}
const fileType = files.type.split('/')[1];
const newFile = files.type === 'binary/octet-stream' ? fileName : `${fileName}.${fileType}`;
if (chunks) {
let count = 1;
chunks.forEach(function (chunk) {
jszip.file(newFile, chunk, { binary: true });
count++;
});
} else {
jszip.file(`${fileName}.${fileType}`, files, { binary: true });
}
jszip.generateAsync({ type: 'blob' }).then((blob) => {
saveAs(blob, `${fileName}.zip`);
resolve(true);
});
}
});
};
/**
* @Title 模拟休眠

View File

@ -15,7 +15,16 @@ import autoprefixer from 'autoprefixer';
import { resolve } from 'path';
export default defineConfig(({ command, mode }) => {
const { VITE_PORT, VITE_APP_NAME } = loadEnv(mode, process.cwd());
const {
VITE_PORT,
VITE_APP_NAME,
VITE_APP_BASE_API,
VITE_APP_BASE_URL,
VITE_APP_UPLOAD_API,
VITE_APP_UPLOAD_URL,
VITE_APP_SYSTEM_API,
VITE_APP_SYSTEM_URL,
} = loadEnv(mode, process.cwd());
const config = {
base: './',
build: {
@ -32,31 +41,20 @@ export default defineConfig(({ command, mode }) => {
'Access-Control-Allow-Origin': '*',
},
proxy: {
// [VITE_APP_BASE_API]: {
// target: VITE_APP_BASE_URL,
// changeOrigin: true,
// rewrite: (path) => path.replace(/^\/apis/, ''),
// },
'^/api': {
target: process.env.VUE_APP_BASE_API, // 开发环境
[VITE_APP_BASE_API]: {
target: VITE_APP_BASE_URL,
changeOrigin: true,
pathRewrite: {
'^/api': '',
},
'^/admin_api': {
target: 'https://mock.mengxuegu.com/mock/65d00eb6351bbd02cf3398e3/api',
changeOrigin: true,
pathRewrite: {
'^/admin_api': '',
},
},
'^/v2api': {
target: 'https://mock.mengxuegu.com/mock/663f2f7737199f49537c350f/api-v2',
changeOrigin: true,
pathRewrite: {
'^/v2api': '',
},
},
rewrite: (path) => path.replace(/^\/apis/, ''),
},
[VITE_APP_UPLOAD_API]: {
target: VITE_APP_UPLOAD_URL,
changeOrigin: true,
rewrite: (path) => path.replace(/^\/uploadApis/, ''),
},
[VITE_APP_SYSTEM_API]: {
target: VITE_APP_SYSTEM_URL,
changeOrigin: true,
rewrite: (path) => path.replace(/^\/systemApis/, ''),
},
},
},

View File

@ -2,5 +2,10 @@
VITE_PORT = 9528
VITE_MODE = 'DEV'
VITE_APP_NAME = 'sub-government-affairs-service'
VITE_APP_BASE_API = '/apis'
VITE_APP_BASE_URL = 'http://localhost:8080/'
VITE_APP_BASE_API = '/traceApis'
VITE_APP_BASE_URL = 'http://192.168.18.99:8080'
VITE_APP_UPLOAD_API = '/uploadApis'
VITE_APP_UPLOAD_URL = 'http://192.168.18.99:9300'
VITE_APP_DICDATA_API = '/dicDataApis'
VITE_APP_DICDATA_URL = 'http://192.168.18.99:99/stage-api'

View File

@ -1,5 +1,5 @@
# 生产环境
VITE_MODE = 'PRO'
VITE_APP_NAME = 'sub-government-affairs-service'
VITE_APP_BASE_API = 'https://www.localhost.com/8080/api/'
VITE_APP_BASE_URL = 'https://www.localhost.com/8080/'
VITE_APP_BASE_API = ''
VITE_APP_BASE_URL = 'http://192.168.18.99:8080/trace'

View File

@ -0,0 +1,73 @@
import request from '@/utils/axios';
/**
* @Title: 列表
*/
export function GetEntityList(params) {
return request('/trace/code/farmMange/page', {
method: 'GET',
params,
});
}
/**
* @Title: 新增
*/
export function AddEntity(data) {
return request('/trace/code/farmMange/save', {
method: 'POST',
data,
});
}
/**
* @Title: 修改
*/
export function UpdateEntity(data) {
return request('/trace/code/farmMange/edit', {
method: 'PUT',
data,
});
}
/**
* @Title: 删除
*/
export function DeleteEntity(params) {
return request('/trace/code/farmMange/delete', {
method: 'DELETE',
params,
});
}
/**
* @Title: 导入
*/
export function ImportEntity(data) {
return request('/trace/code/farmMange/import', {
method: 'POST',
headers: { 'Content-Type': 'multipart/form-data' },
data,
});
}
/**
* @Title: 导出
*/
export function ExportEntity(params) {
return request('/trace/code/farmMange/export', {
method: 'GET',
params,
responseType: 'blob',
});
}
/**
* @Title: 地址列表
*/
export function GetAreaList(params) {
return request('/trace/code/farmMange/areas', {
method: 'GET',
params,
});
}

View File

@ -0,0 +1,27 @@
import request from '@/utils/axios';
import { isEmpty } from '@/utils';
/**
* @Title: 获取字典
*/
export function CommonDicData(params = { pageNum: 1, pageSize: 20, dictType: null }) {
if (isEmpty(params?.dictType)) return;
return request(`/system/dict/data/list`, {
method: 'GET',
apisType: 'dicData',
params,
});
}
/**
* @Title: 上传图片
*/
export function CommonUpload(data, params) {
return request(`/upload`, {
method: 'POST',
apisType: 'upload',
uploadType: 'multipart/form-data',
data,
params,
});
}

View File

@ -1,4 +1,4 @@
import * as components from "../../../main/src/components";
import * as components from '../../../main/src/components';
// 全局注册组件
export const registerGlobalComponents = (app) => {

View File

@ -3,7 +3,7 @@
* @Author: zenghua.wang
* @Date: 2023-06-20 11:48:41
* @LastEditors: zenghua.wang
* @LastEditTime: 2025-01-25 10:49:41
* @LastEditTime: 2025-02-05 09:31:21
*/
import { createRouter, createWebHistory } from 'vue-router';
import { qiankunWindow } from 'vite-plugin-qiankun/dist/helper';
@ -42,7 +42,7 @@ export const constantRoutes = [
},
],
},
...resourceRouter,
// ...resourceRouter,
...plantingAndBreedingRouter,
];

View File

@ -14,17 +14,17 @@ export default [
name: 'planting',
component: Views,
meta: { title: '种植档案', icon: 'Document' },
redirect: '/planting-archives',
redirect: '/planting-base',
children: [
{
path: '/planting-archives',
component: () => import('@/views/trace/planting/archives.vue'),
name: 'planting-archives',
path: '/planting-base',
component: () => import('@/views/trace/planting/base/index.vue'),
name: 'planting-base',
meta: { title: '基地档案', icon: 'Document' },
},
{
path: '/planting-seed',
component: () => import('@/views/trace/planting/seed.vue'),
component: () => import('@/views/trace/planting/seed/index.vue'),
name: 'planting-seed',
meta: { title: '种子档案', icon: 'Document' },
},
@ -35,8 +35,21 @@ export default [
name: 'breeding',
component: Views,
meta: { title: '农事管理', icon: 'Document' },
redirect: '/breeding-land',
children: [],
redirect: '/coding',
children: [
{
path: '/coding',
component: () => import('@/views/trace/breeding/coding/index.vue'),
name: 'coding',
meta: { title: '采收与赋码管理', icon: 'Document' },
},
{
path: '/quality',
component: () => import('@/views/trace/breeding/quality/index.vue'),
name: 'quality',
meta: { title: '产品质检管理', icon: 'Document' },
},
],
},
],
},

View File

@ -5,7 +5,8 @@ import { isEmpty, encode, decode } from '@/utils';
export const useUserStore = defineStore({
id: GenKey('USER_STATE'),
state: () => ({
token: null,
token:
'eyJhbGciOiJIUzUxMiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VyX2tleSI6IjA0ZjNmZTE5LTc5ZWYtNGMxNy1iNWQ4LTE5YjA0MTkyNTZiMyIsInVzZXJuYW1lIjoiYWRtaW4ifQ.nGVLjwzO7K6MO9DbKKhfmwsoinDig5tsGWGEb3jcOtUQHcyJhTTvvuq3zAxNHSFRm9Nly_MSEcRV6oVcz3gT_w',
userInfo: {},
currentOrg: null,
orgList: [],
@ -17,7 +18,8 @@ export const useUserStore = defineStore({
this.token = token;
},
hasToken() {
return !isEmpty(this.token);
return true;
//return !isEmpty(this.token);
},
setUserInfo(userInfo) {
this.userInfo = encode(JSON.stringify(userInfo), true);

View File

@ -102,7 +102,7 @@
font-size: 18px;
}
.el-upload {
display: block;
display: block!important;
width: 100%;
height: 100%;
}

View File

@ -3,7 +3,7 @@
* @Author: zenghua.wang
* @Date: 2022-02-23 21:12:37
* @LastEditors: zenghua.wang
* @LastEditTime: 2024-01-06 11:29:36
* @LastEditTime: 2025-02-07 10:26:41
*/
import axios from 'axios';
import { ElNotification } from 'element-plus';
@ -11,7 +11,7 @@ import router from '@/router';
import { isEmpty } from '@/utils';
import { useUserStore } from '@/store/modules/user';
const { VITE_APP_BASE_API, VITE_APP_UPLOAD_API } = import.meta.env;
const { VITE_APP_BASE_API, VITE_APP_UPLOAD_API, VITE_APP_DICDATA_API } = import.meta.env;
/**
* 创建axios实例
@ -45,15 +45,24 @@ const errorHandler = async (error) => {
*/
publicAxios.interceptors.request.use(async (config) => {
const UserStore = useUserStore();
config.baseURL = config.isUpload ? VITE_APP_UPLOAD_API : VITE_APP_BASE_API;
switch (config.apisType) {
case 'upload': {
config.baseURL = VITE_APP_UPLOAD_API;
config.headers['Content-Type'] = config.uploadType;
break;
}
case 'dicData': {
config.baseURL = VITE_APP_DICDATA_API;
break;
}
default: {
config.baseURL = VITE_APP_BASE_API;
}
}
if (UserStore.hasToken()) {
config.headers['fairies-auth-token'] = config.headers['fairies-auth-token'] ?? UserStore.token;
config.headers['fairies-org-id'] = UserStore.currentOrg;
config.headers['authorization'] = config.headers['authorization'] ?? UserStore.token;
config.headers['cache-control'] = 'no-cache';
config.headers.Pragma = 'no-cache';
if (config?.isUpload) {
config.headers['Content-Type'] = config.uploadType;
}
}
if (config.method === 'POST' || config.method === 'DELETE') {
config.headers.Accept = 'application/json';
@ -76,10 +85,10 @@ const formatResult = (res) => {
case 500:
case 1:
// code === 1 或 500 代表存在错误
ElNotification.error(res.data.message);
ElNotification.error(res.data.msg);
break;
default:
ElNotification.error(res.data.message);
ElNotification.error(res.data.msg);
break;
}
};
@ -91,7 +100,7 @@ publicAxios.interceptors.response.use((response) => {
if (config?.responseType) {
return response;
}
const token = response?.headers['fairies-auth-token'];
const token = response?.headers['authorization'];
if (!isEmpty(token)) {
const UserStore = useUserStore();
UserStore.setToken(token);
@ -100,7 +109,7 @@ publicAxios.interceptors.response.use((response) => {
if (result) {
return result;
}
throw new Error(response.data.message);
throw new Error(response.data.msg);
}, errorHandler);
export default publicAxios;

View File

@ -3,10 +3,10 @@
* @Author: zenghua.wang
* @Date: 2022-02-23 21:12:37
* @LastEditors: zenghua.wang
* @LastEditTime: 2025-01-25 17:04:22
* @LastEditTime: 2025-02-07 15:21:48
*/
import lodash from 'lodash';
import moment from 'moment';
import dayjs from 'dayjs';
import { Base64 } from 'js-base64';
/**
@ -90,7 +90,7 @@ export const setDefaultOption = (options, prop, defaultVal) => {
return options[prop] === undefined ? defaultVal : options.prop;
};
/**
* 设置字典值
* @Title 设置字典值
* @param {*} columns
* @param {*} key
* @param {*} data
@ -107,7 +107,7 @@ export const setDicData = (columns, key, data = []) => {
}
};
/**
* 求字段lable
* @Title 求字段lable
* @param {*} tree
* @returns
*/
@ -124,7 +124,35 @@ export const setDicLabel = (dicData, value) => {
return label;
};
/**
* 加密
* @Title 数组交集
* @param {*} arr1
* @param {*} arr2
* @returns
*/
export const intersectionArray = (arr1 = [], arr2 = []) => {
return arr1.filter((item) => arr2.includes(item));
};
/**
* @Title 数组并集
* @param {*} arr1
* @param {*} arr2
* @returns
*/
export const unionArray = (arr1 = [], arr2 = []) => {
return Array.from(new Set([...arr1, ...arr2]));
};
/**
* @Title 数组差集
* @param {*} arr1
* @param {*} arr2
* @returns
*/
export const differenceArray = (arr1 = [], arr2 = []) => {
const s = new Set(arr2);
return arr1.filter((x) => !s.has(x));
};
/**
* @Title 加密
* @param {*} n
* @returns
*/
@ -146,7 +174,7 @@ export const encode = (n, flag = false) => {
return n;
};
/**
* 解密
* @Title 解密
* @param {*} e
* @returns
*/
@ -190,6 +218,22 @@ export const imageToBase64 = (file) => {
export const bufferToBase64 = (buffer) => {
return 'data:image/jpeg;base64,' + window.btoa(new Uint8Array(buffer).reduce((data, byte) => data + String.fromCharCode(byte), ''));
};
/**
* @Title blob转json
* @param {*} file
* @returns
*/
export const blobToJSON = (blob) => {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsText(blob, 'utf-8');
reader.onload = () => {
const res = !isEmpty(reader.result) ? JSON.parse(reader.result) : reader.result;
resolve(res);
};
reader.onerror = reject;
});
};
/**
* @Title 将array转化为树
* @param tree
@ -227,22 +271,27 @@ export const getUrlQuery = (name) => {
const usp = new URLSearchParams(search);
return usp.get(name);
};
/**
* @Title 将Object参数转换为字符串
* @param {*} json
* @returns
*/
export const obj2Param = (json) => {
if (!json) return '';
return Object.keys(json)
.map((key) => {
if (isEmpty(json[key])) return '';
return encodeURIComponent(key) + '=' + encodeURIComponent(json[key]);
})
.join('&');
};
/**
* @Title 获取静态资源文件
* @param {*} url
* @returns
*/
export const getAssetsFile = (url) => {
return new URL(`../assets/images/${url}`, import.meta.url);
};
/**
* @Title 替换图片url字段值
* @param {*} url
* @returns
*/
export const setUploadField = (url) => {
if (isEmpty(url) || url.includes('http')) return null;
return url;
return new URL(`../assets/${url}`, import.meta.url);
};
/**
* @Title: a链接方式文件下载
@ -250,7 +299,22 @@ export const setUploadField = (url) => {
* @param {void} fileName:
* @return {void}
*/
export const dowloadLink = (content, fileName) => {
export const downloadLink = (url, fileName) => {
const elink = document.createElement('a');
elink.download = fileName;
elink.style.display = 'none';
elink.href = url;
elink.target = '_blank';
elink.click();
elink.remove();
};
/**
* @Title: 下载文件
* @param {void} content:
* @param {void} fileName:
* @return {void}
*/
export const downloadFile = (content, fileName) => {
const blob = new Blob([content]);
if ('download' in document.createElement('a')) {
const elink = document.createElement('a');
@ -275,20 +339,106 @@ export const sleep = (duration = 0) =>
setTimeout(resolve, duration);
});
/**
* 日期格式化
* @Title 创建id
* @param {*} prefix
* @returns
*/
export const createId = (prefix) => {
const val = Date.now() + Math.ceil(Math.random() * 99999);
return isEmpty(prefix) ? val : prefix + '-' + val;
};
/**
* @Title 生成数据
* @param {*} duration
* @returns
*/
export const mockData = (item = {}, len = 1) => {
const list = [];
for (let i = 0; i < len; i++) {
let temp = { ...item, id: createId() };
list.push(temp);
}
return list;
};
/**
* @Title 日期格式化
* @param {*} date
* @param {*} format
* @returns
*/
export const dateFormat = (datetime, type = 'yyyy-MM-dd') => {
return moment(datetime).format(type);
export const dateFormat = (datetime, formater = 'YYYY-MM-DD hh:mm:ss') => {
if (datetime instanceof Date || datetime) {
return dayjs(datetime).format(formater);
} else {
return null;
}
};
/**
* 上日///
* @Title 字符串转日期
* @param {*} str
* @returns
*/
export const lastDate = (last = 0, date = 'month', type = 'yyyy-MM-dd') => {
if (date === 'day') {
return moment().subtract(last, 'day').endOf('day').format(type);
}
return moment().subtract(last, date).format(type);
export const toDate = (str) => {
return !isEmpty(str) ? dayjs(str) : dayjs();
};
/**
* @Title 字符串转日期
* @param {*} str
* @returns
*/
export const getDate = (num, type, formater = 'YYYY-MM-DD', start = true) => {
const date = dayjs().subtract(num, type);
return start ? date.startOf(type).format(formater) : date.endOf(type).format(formater);
};
/**
* @Title: 获取时间差
* @param start
* @param end
* @param type
* @returns
*/
export const getDiffTime = (start, end, type) => {
const startTime = dayjs(start);
const endTime = dayjs(end);
const duration = endTime.diff(startTime);
let diff = 0;
switch (type) {
case 'DD': {
diff = duration / (1000 * 60 * 60 * 24);
break;
}
case 'HH': {
diff = duration / (1000 * 60 * 60);
break;
}
case 'mm': {
diff = duration / (1000 * 60);
break;
}
}
return Math.round(diff);
};
/**
* @Title: 开始日期
* @param last
* @param type
* @param formater
* @returns
*/
export const startDate = (num, type = 'month', formater = 'YYYY-MM-DD HH:mm:ss') => {
if (num === 'now') return dayjs().format(formater);
if (typeof num === 'string') return dayjs(num).startOf(type).format(formater);
return num === 0 ? dayjs().startOf(type).format(formater) : dayjs().subtract(num, type).startOf(type).format(formater);
};
/**
* @Title: 结束日期
* @param num
* @param type
* @param formater
* @returns
*/
export const endDate = (num = 0, type = 'month', formater = 'YYYY-MM-DD HH:mm:ss') => {
if (num === 'now') return dayjs().format(formater);
if (typeof num === 'string') return dayjs(num).endOf(type).format(formater);
return num === 0 ? dayjs().endOf(type).format(formater) : dayjs().subtract(num, type).endOf(type).format(formater);
};

View File

@ -0,0 +1,540 @@
<template>
<div class="custom-page">
<avue-crud
ref="crudRef"
v-model="state.form"
v-model:search="state.query"
v-model:page="state.pageData"
:table-loading="state.loading"
:data="state.data"
:option="state.options"
@size-change="sizeChange"
@current-change="currentChange"
@refresh-change="refreshChange"
@search-reset="searchChange"
@search-change="searchChange"
@selection-change="selectionChange"
@row-save="rowSave"
@row-update="rowUpdate"
@row-del="rowDel"
>
<template #menu-left>
<el-button type="danger" icon="delete" @click="onDel(state.selection)">批量删除</el-button>
<el-button type="success" icon="upload" @click="onUpload">导入</el-button>
<el-button type="success" icon="download" @click="onExport">导出</el-button>
</template>
<template #qualityReportUrl="{ row }">
<el-button v-if="row.qualityReportUrl" type="primary" text @click="downloadLink(row.qualityReportUrl, `${row.productName}-质检报告.pdf`)">
下载
</el-button>
<span v-else>暂无</span>
</template>
<template #productUrl-form="{ column }">
<el-upload class="custom-form__uploader" action="#" :show-file-list="false" accept="image/*" :limit="1" :http-request="rowUploadPicture">
<img v-if="state.form.base64" :src="state.form.base64" class="custom-form__uploader__img" />
<el-icon v-else class="custom-form__uploader__icon"><Plus /></el-icon>
</el-upload>
</template>
<template #menu="scope">
<custom-table-operate :actions="state.options.actions" :data="scope" />
</template>
</avue-crud>
<custom-import-excel
ref="importExcelRef"
:template-url="getAssetsFile('template/采收赋码-导入模板.xlsx')"
@on-download="onDownloadExcel"
@on-confirm="onUploadExcel"
/>
</div>
</template>
<script setup>
import { reactive, ref } from 'vue';
import { useApp } from '@/hooks';
import { CRUD_OPTIONS } from '@/config';
import { isEmpty, imageToBase64, getAssetsFile, downloadLink, downloadFile } from '@/utils';
import { useUserStore } from '@/store/modules/user';
import { CommonUpload } from '@/apis';
import { GetEntityList, GetAreaList, AddEntity, UpdateEntity, DeleteEntity, ImportEntity, ExportEntity } from '@/apis/coding';
const { VITE_APP_DICDATA_API, VITE_APP_BASE_API } = import.meta.env;
const app = useApp();
const UserStore = useUserStore();
const crudRef = ref(null);
const importExcelRef = ref(null);
const state = reactive({
loading: false,
query: {
current: 1,
size: 10,
},
form: {},
selection: [],
options: {
...CRUD_OPTIONS,
addBtnText: '添加信息',
column: [
{
label: '溯源码',
prop: 'id',
search: true,
display: false,
width: 200,
},
{
label: '采收批次',
prop: 'harvestBatch',
width: 200,
display: false,
// rules: {
// required: true,
// message: '',
// trigger: 'blur',
// },
},
{
label: '产品名称',
prop: 'productName',
search: true,
width: 200,
rules: {
required: true,
message: '请输入',
trigger: 'blur',
},
},
{
label: '产品种类',
prop: 'productType',
type: 'select',
search: true,
props: {
label: 'dictLabel',
value: 'dictValue',
},
dicUrl: `${VITE_APP_DICDATA_API}/system/dict/data/list?pageNum=1&pageSize=20&dictType=sys_product_type`,
dicHeaders: {
authorization: UserStore.token,
},
dicFormatter: (res) => res?.data?.records ?? [],
rules: {
required: true,
message: '请选择',
trigger: 'blur',
},
},
{
label: '数量',
prop: 'number',
type: 'number',
rules: {
required: true,
message: '请输入',
trigger: 'blur',
},
},
{
label: '单位',
prop: 'unit',
type: 'select',
props: {
label: 'dictLabel',
value: 'dictValue',
},
dicUrl: `${VITE_APP_DICDATA_API}/system/dict/data/list?pageNum=1&pageSize=20&dictType=sys_unit_type`,
dicHeaders: {
authorization: UserStore.token,
},
dicFormatter: (res) => res?.data?.records ?? [],
rules: {
required: true,
message: '请选择',
trigger: 'blur',
},
},
{
label: '保质期',
prop: 'qualityGuaranteePeriod',
type: 'number',
rules: {
required: true,
message: '请输入',
trigger: 'blur',
},
formatter: (row) => {
return row.qualityGuaranteePeriod + '天';
},
},
{
label: '质检结果',
prop: 'qualityResult',
display: false,
},
{
label: '质检报告',
prop: 'qualityReportUrl',
display: false,
slot: true,
},
{
label: '采收日期',
prop: 'datetime',
type: 'datetimerange',
searchRange: true,
search: true,
searchSpan: 8,
rangeSeparator: '至',
startPlaceholder: '开始日期',
endPlaceholder: '结束日期',
format: 'YYYY-MM-DD HH:mm:ss',
valueFormat: 'YYYY-MM-DD HH:mm:ss',
width: 200,
hide: true,
display: false,
},
{
label: '采收日期',
prop: 'harvestTime',
type: 'date',
format: 'YYYY-MM-DD',
valueFormat: 'YYYY-MM-DD',
width: 200,
rules: {
required: true,
message: '请输入',
trigger: 'blur',
},
},
{
label: '省',
prop: 'province',
hide: true,
display: false,
},
{
label: '市',
prop: 'city',
hide: true,
display: false,
},
{
label: '县/区',
prop: 'county',
hide: true,
display: false,
},
{
label: '乡镇',
prop: 'village',
hide: true,
display: false,
},
{
label: '原产地',
prop: 'originAddress',
type: 'cascader',
search: true,
overHidden: true,
width: 200,
props: {
// expandTrigger: 'click',
label: 'areaName',
value: 'areaCode',
children: 'areaChildVOS',
lazy: true,
lazyLoad: async (node, resolve) => {
console.log(361, node);
const { data } = await GetAreaList({ areaCode: node.value });
resolve(data ?? []);
},
},
dicUrl: `${VITE_APP_BASE_API}/trace/code/farmMange/areas`,
dicHeaders: {
authorization: UserStore.token,
},
dicFormatter: (res) => res?.data ?? [],
rules: {
required: true,
message: '请选择',
trigger: 'blur',
},
},
{
label: '原产地详细地址',
prop: 'originAddressDetail',
hide: true,
span: 24,
},
// {
// label: '',
// prop: 'businessName',
// search: true,
// rules: {
// required: true,
// message: '',
// trigger: 'blur',
// },
// },
{
label: '产品图片',
prop: 'productUrl',
type: 'upload',
span: 24,
hide: true,
formslot: true,
rules: {
required: true,
message: '请输入',
trigger: 'blur',
},
},
{
label: '农事记录',
prop: 'farmRecord',
type: 'textarea',
span: 24,
rows: 4,
overHidden: true,
width: 200,
rules: {
required: true,
message: '请输入',
trigger: 'blur',
},
},
{
label: '创建时间',
prop: 'createTime',
width: 200,
display: false,
},
],
actions: [
{
name: '查看',
icon: 'view',
event: ({ row }) => rowView(row),
},
{
name: '编辑',
icon: 'edit',
event: ({ row }) => rowEdit(row),
},
{
type: 'danger',
name: '删除',
icon: 'delete',
event: ({ row }) => rowDel(row),
},
],
},
pageData: {
total: 0,
currentPage: 1,
pageSize: 10,
},
data: [],
});
const loadData = async () => {
state.loading = true;
GetEntityList(state.query)
.then((res) => {
if (res.code === 200) {
const { current, size, total, records } = res.data;
state.data = records;
state.pageData = {
currentPage: current || 1,
pageSize: size || 10,
total: total,
};
}
})
.catch((err) => {
app.$message.error(err.msg);
})
.finally(() => {
state.loading = false;
});
};
// GetAreaList();
loadData();
//
const currentChange = (current) => {
state.query.current = current;
loadData();
};
//
const sizeChange = (size) => {
state.query.size = size;
loadData();
};
//
const searchChange = (params, done) => {
if (done) done();
state.query = params;
if (params?.datetime) {
state.query.harvestStartTime = params.datetime[0];
state.query.harvestEndTime = params.datetime[1];
}
state.query.current = 1;
loadData();
};
//
const refreshChange = () => {
loadData();
app.$message.success('刷新成功');
};
//
const selectionChange = (rows) => {
state.selection = rows;
};
//
const rowView = (row) => {
row.base64 = row.productUrl;
crudRef.value.rowView(row);
};
//
const rowUploadPicture = async ({ file }) => {
if (isEmpty(file.name)) return;
const formData = new FormData();
formData.append('file', file);
const res = await CommonUpload(formData);
if (res.code === 200) {
state.form.productUrl = res.data.url;
const base64 = await imageToBase64(file);
state.form.base64 = base64;
}
};
//
const rowSave = (row, done, loading) => {
delete row.base64;
AddEntity(row)
.then((res) => {
if (res.code === 200) {
app.$message.success('添加成功!');
done();
loadData();
}
})
.catch((err) => {
app.$message.error(err.msg);
})
.finally(() => {
loading();
});
};
//
const rowEdit = (row) => {
row.base64 = row.productUrl;
crudRef.value.rowEdit(row);
};
const rowUpdate = (row, index, done, loading) => {
delete row.base64;
UpdateEntity(row)
.then((res) => {
if (res.code === 200) {
app.$message.success('更新成功!');
done();
loadData();
}
})
.catch((err) => {
app.$message.error(err.msg);
})
.finally(() => {
loading();
});
};
//
const onDel = (rows = []) => {
if (isEmpty(rows)) return;
const ids = rows.map((item) => item.id);
app
.$confirm(`删除后信息将不可查看,确认要删除吗?`, '确定删除', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
.then(() => {
DeleteEntity({ ids: ids.join(',') })
.then((res) => {
if (res.code === 200) {
app.$message.success('删除成功!');
loadData();
}
})
.catch((err) => {
app.$message.error(err.msg);
});
})
.catch(() => {});
};
const rowDel = (row, index, done) => {
onDel([row]);
};
//
const onUpload = () => {
importExcelRef?.value && importExcelRef.value.show();
};
const onUploadExcel = (formData) => {
ImportEntity(formData)
.then((res) => {
if (res.status === 200) {
app.$message.success('导入成功!');
}
})
.catch((err) => {
app.$message.error('导入失败!');
importExcelRef.value.clear();
})
.finally(() => {
importExcelRef.value.hide();
});
};
const onDownloadExcel = (url) => {
downloadLink(url, `采收赋码-导入模板.xlsx`);
};
//
const onExport = () => {
if (isEmpty(state.data)) {
app.$message.error('当前暂时没有可供导出的数据!');
return;
}
state.loading = true;
const fileName = '采收与赋码明细表';
ExportEntity(state.query)
.then((res) => {
if (res.status === 200) {
downloadFile(res.data, `${fileName}.xlsx`);
app.$message.success('导出成功!');
}
})
.catch((err) => {
app.$message.error('导出失败!');
})
.finally(() => {
state.loading = false;
});
};
</script>

View File

@ -0,0 +1,3 @@
<template>
<div>产品质检管理</div>
</template>

View File

@ -31,11 +31,6 @@ import { useApp } from '@/hooks';
import { sleep } from '@/utils';
import { CRUD_OPTIONS } from '@/config';
import { useSettingStore } from '@/store/modules/setting';
const SettingStore = useSettingStore();
const globalComSize = computed(() => SettingStore.themeConfig.globalComSize);
import Mock from 'mockjs';
const res = Mock.mock({
'data|20': [
@ -64,8 +59,7 @@ const state = reactive({
selection: [],
options: {
...CRUD_OPTIONS,
addBtnText: '新增档案',
size: globalComSize.value,
addBtnText: '添加档案',
column: [
{
label: '基地代码',
@ -116,7 +110,7 @@ const state = reactive({
],
rules: {
required: true,
message: '请输入',
message: '请选择',
trigger: 'blur',
},
},
@ -145,7 +139,7 @@ const state = reactive({
],
rules: {
required: true,
message: '请输入',
message: '请选择',
trigger: 'blur',
},
},
@ -165,7 +159,7 @@ const state = reactive({
],
rules: {
required: true,
message: '请输入',
message: '请选择',
trigger: 'blur',
},
},
@ -173,13 +167,16 @@ const state = reactive({
label: '面积(亩)',
prop: 'area',
type: 'number',
labelTip: '提示语',
labelTipPlacement: 'bottom',
// labelTip: '',
// labelTipPlacement: 'bottom',
rules: {
required: true,
message: '请输入',
trigger: 'blur',
},
formatter: (row) => {
return row.area + '亩';
},
},
{
label: '海拔(米)',
@ -190,6 +187,9 @@ const state = reactive({
message: '请输入',
trigger: 'blur',
},
formatter: (row) => {
return row.area + 'm';
},
},
{
label: '创建日期',

View File

@ -54,7 +54,7 @@ const state = reactive({
selection: [],
options: {
...CRUD_OPTIONS,
addBtnText: '新增档案',
addBtnText: '添加档案',
column: [
{
label: '种子代码',

View File

@ -2,8 +2,8 @@
* @Descripttion:
* @Author: zenghua.wang
* @Date: 2022-09-18 21:24:29
* @LastEditors: zenghua.wang 1048523306@qq.com
* @LastEditTime: 2025-01-21 14:11:58
* @LastEditors: zenghua.wang
* @LastEditTime: 2025-02-07 10:01:57
*/
import { defineConfig, loadEnv } from 'vite';
@ -24,7 +24,16 @@ const useDevMode = true;
export default defineConfig(({ command, mode }) => {
console.log('vite.config.js', command, mode, loadEnv(mode, process.cwd()));
const { VITE_PORT, VITE_APP_NAME, VITE_APP_BASE_API, VITE_APP_BASE_URL, VITE_APP_UPLOAD_API, VITE_APP_UPLOAD_URL } = loadEnv(mode, process.cwd());
const {
VITE_PORT,
VITE_APP_NAME,
VITE_APP_BASE_API,
VITE_APP_BASE_URL,
VITE_APP_UPLOAD_API,
VITE_APP_UPLOAD_URL,
VITE_APP_DICDATA_API,
VITE_APP_DICDATA_URL,
} = loadEnv(mode, process.cwd());
const config = {
base: './',
build: {
@ -44,13 +53,18 @@ export default defineConfig(({ command, mode }) => {
[VITE_APP_BASE_API]: {
target: VITE_APP_BASE_URL,
changeOrigin: true,
rewrite: (path) => path.replace(/^\/apis/, ''),
rewrite: (path) => path.replace(/^\/traceApis/, ''),
},
[VITE_APP_UPLOAD_API]: {
target: VITE_APP_UPLOAD_URL,
changeOrigin: true,
rewrite: (path) => path.replace(/^\/uploadApis/, ''),
},
[VITE_APP_DICDATA_API]: {
target: VITE_APP_DICDATA_URL,
changeOrigin: true,
rewrite: (path) => path.replace(/^\/dicDataApis/, ''),
},
},
},
resolve: {