Merge 1717bcbfd0
into 6a7019ec1a
commit
f3eb7004cc
|
@ -77,5 +77,6 @@ declare module '@vue/runtime-core' {
|
|||
TableEdit: typeof import('./src/components/table-edit.vue')['default']
|
||||
TableSearch: typeof import('./src/components/table-search.vue')['default']
|
||||
Tabs: typeof import('./src/components/tabs.vue')['default']
|
||||
WeatherWidget: typeof import('./src/components/WeatherWidget.vue')['default']
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
<!-- src/components/WeatherWidget.vue -->
|
||||
<template>
|
||||
<el-card shadow="hover" class="weather-widget">
|
||||
<div class="weather-header">
|
||||
<el-icon class="weather-icon">
|
||||
<Sunny />
|
||||
</el-icon>
|
||||
<div class="weather-info">
|
||||
<div class="weather-temp">{{ weather.temp }}°C</div>
|
||||
<div class="weather-desc">{{ weather.description }}</div>
|
||||
<div class="weather-city">{{weather.city}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { Sunny } from '@element-plus/icons-vue';
|
||||
|
||||
const weather = ref({
|
||||
temp: 0,
|
||||
description: 'Loading...',
|
||||
});
|
||||
|
||||
const fetchWeather = async () => {
|
||||
try {
|
||||
const response = await fetch('https://restapi.amap.com/v3/weather/weatherInfo?key= &city=230103&extensions=base');
|
||||
const data = await response.json();
|
||||
if (data.status === '1' && data.lives && data.lives.length > 0) {
|
||||
weather.value.temp = data.lives[0].temperature;
|
||||
weather.value.description = data.lives[0].weather;
|
||||
weather.value.city = data.lives[0].city;
|
||||
|
||||
} else {
|
||||
throw new Error('Invalid weather data');
|
||||
}
|
||||
} catch (error) {
|
||||
ElMessage.error('Failed to fetch weather data');
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
fetchWeather();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.weather-widget {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.weather-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.weather-icon {
|
||||
font-size: 50px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.weather-info {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.weather-temp {
|
||||
font-size: 30px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.weather-desc {
|
||||
font-size: 14px;
|
||||
color: #999;
|
||||
}
|
||||
</style>
|
|
@ -31,6 +31,18 @@ export const menuData: Menus[] = [
|
|||
index: '/system-menu',
|
||||
title: '菜单管理',
|
||||
},
|
||||
{
|
||||
id: '14',
|
||||
pid: '1',
|
||||
index: '/product-management',
|
||||
title: '商品管理',
|
||||
},
|
||||
{
|
||||
id: '15',
|
||||
pid: '1',
|
||||
index: '/finance-management',
|
||||
title: '财务管理',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
|
|
@ -50,6 +50,24 @@ const routes: RouteRecordRaw[] = [
|
|||
},
|
||||
component: () => import(/* webpackChunkName: "system-menu" */ '../views/system/menu.vue'),
|
||||
},
|
||||
{
|
||||
path: '/product-management',
|
||||
name: 'product-management',
|
||||
meta: {
|
||||
title: '商品管理',
|
||||
permiss: '14',
|
||||
},
|
||||
component: () => import(/* webpackChunkName: "product-management" */ '../views/product-management.vue'),
|
||||
},
|
||||
{
|
||||
path: '/finance-management',
|
||||
name: 'finance-management',
|
||||
meta: {
|
||||
title: '财务管理',
|
||||
permiss: '15',
|
||||
},
|
||||
component: () => import(/* webpackChunkName: "finance-management" */ '../views/finance-management.vue'),
|
||||
},
|
||||
{
|
||||
path: '/table',
|
||||
name: 'basetable',
|
||||
|
|
|
@ -13,6 +13,8 @@ export const usePermissStore = defineStore('permiss', {
|
|||
'11',
|
||||
'12',
|
||||
'13',
|
||||
'14',
|
||||
'15',
|
||||
'2',
|
||||
'21',
|
||||
'22',
|
||||
|
@ -43,7 +45,7 @@ export const usePermissStore = defineStore('permiss', {
|
|||
'65',
|
||||
'66',
|
||||
],
|
||||
user: ['0', '1', '11', '12', '13'],
|
||||
user: ['0', '1', '11', '12', '13', '14', '15'],
|
||||
};
|
||||
const username = localStorage.getItem('vuems_name');
|
||||
console.log(username);
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-row :gutter="20" class="mgb20">
|
||||
<el-col :span="6">
|
||||
<WeatherWidget />
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20" class="mgb20">
|
||||
<el-col :span="6">
|
||||
<el-card shadow="hover" body-class="card-body">
|
||||
|
@ -127,6 +132,7 @@
|
|||
</template>
|
||||
|
||||
<script setup lang="ts" name="dashboard">
|
||||
import WeatherWidget from '@/components/WeatherWidget.vue';
|
||||
import countup from '@/components/countup.vue';
|
||||
import { use, registerMap } from 'echarts/core';
|
||||
import { BarChart, LineChart, PieChart, MapChart } from 'echarts/charts';
|
||||
|
|
|
@ -0,0 +1,113 @@
|
|||
<template>
|
||||
<div>
|
||||
<h1>财务管理</h1>
|
||||
<el-button type="primary" @click="openDialog">新增记录</el-button>
|
||||
<el-table :data="records" style="width: 100%">
|
||||
<el-table-column prop="date" label="日期" width="180"></el-table-column>
|
||||
<el-table-column prop="amount" label="金额" width="180"></el-table-column>
|
||||
<el-table-column prop="description" label="描述" width="180"></el-table-column>
|
||||
<el-table-column label="操作" width="180">
|
||||
<template #default="scope">
|
||||
<el-button @click="editRecord(scope.row)" type="primary" size="small">编辑</el-button>
|
||||
<el-button @click="deleteRecord(scope.row)" type="danger" size="small">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<el-dialog :title="isEdit ? '编辑记录' : '新增记录'" v-model="dialogVisible">
|
||||
<el-form :model="form">
|
||||
<el-form-item label="日期">
|
||||
<el-date-picker v-model="form.date" type="date" placeholder="选择日期"></el-date-picker>
|
||||
</el-form-item>
|
||||
<el-form-item label="金额">
|
||||
<el-input v-model="form.amount"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="描述">
|
||||
<el-input v-model="form.description"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="dialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="saveRecord">保存</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="finance-management">
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
|
||||
const records = ref([]);
|
||||
const dialogVisible = ref(false);
|
||||
const isEdit = ref(false);
|
||||
const form = ref({
|
||||
date: '',
|
||||
amount: '',
|
||||
description: '',
|
||||
});
|
||||
|
||||
const fetchRecords = async () => {
|
||||
try {
|
||||
const response = await fetch('/api/finance-records');
|
||||
const data = await response.json();
|
||||
records.value = data;
|
||||
} catch (error) {
|
||||
ElMessage.error('Failed to fetch financial records');
|
||||
}
|
||||
};
|
||||
|
||||
const openDialog = () => {
|
||||
isEdit.value = false;
|
||||
form.value = { date: '', amount: '', description: '' };
|
||||
dialogVisible.value = true;
|
||||
};
|
||||
|
||||
const editRecord = (record) => {
|
||||
isEdit.value = true;
|
||||
form.value = { ...record };
|
||||
dialogVisible.value = true;
|
||||
};
|
||||
|
||||
const saveRecord = async () => {
|
||||
try {
|
||||
if (isEdit.value) {
|
||||
// Update record
|
||||
await fetch(`/api/finance-records/${form.value.id}`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(form.value),
|
||||
});
|
||||
} else {
|
||||
// Add new record
|
||||
await fetch('/api/finance-records', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(form.value),
|
||||
});
|
||||
}
|
||||
fetchRecords();
|
||||
dialogVisible.value = false;
|
||||
ElMessage.success('Record saved successfully');
|
||||
} catch (error) {
|
||||
ElMessage.error('Failed to save record');
|
||||
}
|
||||
};
|
||||
|
||||
const deleteRecord = async (record) => {
|
||||
try {
|
||||
await fetch(`/api/finance-records/${record.id}`, { method: 'DELETE' });
|
||||
fetchRecords();
|
||||
ElMessage.success('Record deleted successfully');
|
||||
} catch (error) {
|
||||
ElMessage.error('Failed to delete record');
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
fetchRecords();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
|
@ -0,0 +1,113 @@
|
|||
<template>
|
||||
<div>
|
||||
<h1>商品管理</h1>
|
||||
<el-button type="primary" @click="openDialog">新增商品</el-button>
|
||||
<el-table :data="products" style="width: 100%">
|
||||
<el-table-column prop="name" label="商品名称" width="180"></el-table-column>
|
||||
<el-table-column prop="price" label="价格" width="180"></el-table-column>
|
||||
<el-table-column prop="category" label="分类" width="180"></el-table-column>
|
||||
<el-table-column label="操作" width="180">
|
||||
<template #default="scope">
|
||||
<el-button @click="editProduct(scope.row)" type="primary" size="small">编辑</el-button>
|
||||
<el-button @click="deleteProduct(scope.row)" type="danger" size="small">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<el-dialog :title="isEdit ? '编辑商品' : '新增商品'" v-model="dialogVisible">
|
||||
<el-form :model="form">
|
||||
<el-form-item label="商品名称">
|
||||
<el-input v-model="form.name"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="价格">
|
||||
<el-input v-model="form.price"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="分类">
|
||||
<el-input v-model="form.category"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="dialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="saveProduct">保存</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="product-management">
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
|
||||
const products = ref([]);
|
||||
const dialogVisible = ref(false);
|
||||
const isEdit = ref(false);
|
||||
const form = ref({
|
||||
name: '',
|
||||
price: '',
|
||||
category: '',
|
||||
});
|
||||
|
||||
const fetchProducts = async () => {
|
||||
try {
|
||||
const response = await fetch('/api/products');
|
||||
const data = await response.json();
|
||||
products.value = data;
|
||||
} catch (error) {
|
||||
ElMessage.error('Failed to fetch product data');
|
||||
}
|
||||
};
|
||||
|
||||
const openDialog = () => {
|
||||
isEdit.value = false;
|
||||
form.value = { name: '', price: '', category: '' };
|
||||
dialogVisible.value = true;
|
||||
};
|
||||
|
||||
const editProduct = (product) => {
|
||||
isEdit.value = true;
|
||||
form.value = { ...product };
|
||||
dialogVisible.value = true;
|
||||
};
|
||||
|
||||
const saveProduct = async () => {
|
||||
try {
|
||||
if (isEdit.value) {
|
||||
// Update product
|
||||
await fetch(`/api/products/${form.value.id}`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(form.value),
|
||||
});
|
||||
} else {
|
||||
// Add new product
|
||||
await fetch('/api/products', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(form.value),
|
||||
});
|
||||
}
|
||||
fetchProducts();
|
||||
dialogVisible.value = false;
|
||||
ElMessage.success('Product saved successfully');
|
||||
} catch (error) {
|
||||
ElMessage.error('Failed to save product');
|
||||
}
|
||||
};
|
||||
|
||||
const deleteProduct = async (product) => {
|
||||
try {
|
||||
await fetch(`/api/products/${product.id}`, { method: 'DELETE' });
|
||||
fetchProducts();
|
||||
ElMessage.success('Product deleted successfully');
|
||||
} catch (error) {
|
||||
ElMessage.error('Failed to delete product');
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
fetchProducts();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
Loading…
Reference in New Issue