19 changed files with 637 additions and 22 deletions
@ -0,0 +1,3 @@ |
|||||
|
NODE_ENV=development |
||||
|
VITE_APP_TITLE='律师公益法律服务活动申报与管理平台' |
||||
|
VITE_APP_API_URL='http://127.0.0.1:1024' |
||||
@ -0,0 +1,3 @@ |
|||||
|
NODE_ENV=development |
||||
|
VITE_APP_TITLE='律师公益法律服务活动申报与管理平台' |
||||
|
VITE_APP_API_URL='http://127.0.0.1:1024' |
||||
@ -0,0 +1,3 @@ |
|||||
|
NODE_ENV=production |
||||
|
VITE_APP_TITLE='律师公益法律服务活动申报与管理平台' |
||||
|
VITE_APP_API_URL='https://preview.smartadmin.vip/smart-admin-api' |
||||
@ -0,0 +1,3 @@ |
|||||
|
NODE_ENV=production |
||||
|
VITE_APP_TITLE='律师公益法律服务活动申报与管理平台' |
||||
|
VITE_APP_API_URL='https://preview.smartadmin.vip/smart-admin-api' |
||||
@ -0,0 +1,3 @@ |
|||||
|
NODE_ENV=production |
||||
|
VITE_APP_TITLE='律师公益法律服务活动申报与管理平台' |
||||
|
VITE_APP_API_URL='http://127.0.0.1:1024' |
||||
@ -0,0 +1,18 @@ |
|||||
|
|
||||
|
*.sh |
||||
|
node_modules |
||||
|
lib |
||||
|
*.md |
||||
|
*.woff |
||||
|
*.ttf |
||||
|
.vscode |
||||
|
.idea |
||||
|
dist |
||||
|
public |
||||
|
/docs |
||||
|
.husky |
||||
|
.local |
||||
|
.localhost |
||||
|
/bin |
||||
|
Dockerfile |
||||
|
src/assets |
||||
@ -0,0 +1,66 @@ |
|||||
|
/* |
||||
|
* @Description: |
||||
|
* @Author: zhuoda |
||||
|
* @Date: 2021-11-05 |
||||
|
* @LastEditTime: 2022-07-05 |
||||
|
* @LastEditors: zhuoda |
||||
|
*/ |
||||
|
module.exports = { |
||||
|
root: true, //此项是用来告诉eslint找当前配置文件不能往父级查找 |
||||
|
env: { |
||||
|
browser: true, |
||||
|
es2021: true, |
||||
|
node: true, |
||||
|
}, |
||||
|
parser: 'vue-eslint-parser', //使用vue-eslint-parser 来解析vue文件中的 template和script |
||||
|
parserOptions: { |
||||
|
ecmaVersion: 12, // 默认情况下,ESLint使用的是ECMAScript5语法,此处我们设置的选项是 es12 |
||||
|
sourceType: 'module', // 指定js导入的方式 |
||||
|
}, |
||||
|
extends: ['plugin:vue/vue3-essential', 'eslint:recommended', 'plugin:vue/base'], |
||||
|
globals: { |
||||
|
defineProps: 'readonly', |
||||
|
defineEmits: 'readonly', |
||||
|
defineExpose: 'readonly', |
||||
|
withDefaults: 'readonly', |
||||
|
}, |
||||
|
plugins: ['vue'], |
||||
|
rules: { |
||||
|
'no-unused-vars': [ |
||||
|
'error', |
||||
|
// we are only using this rule to check for unused arguments since TS |
||||
|
// catches unused variables but not args. |
||||
|
{ varsIgnorePattern: '.*', args: 'none' }, |
||||
|
], |
||||
|
'space-before-function-paren': 'off', |
||||
|
|
||||
|
'vue/attributes-order': 'off', |
||||
|
'vue/one-component-per-file': 'off', |
||||
|
'vue/html-closing-bracket-newline': 'off', |
||||
|
'vue/max-attributes-per-line': 'off', |
||||
|
'vue/multiline-html-element-content-newline': 'off', |
||||
|
'vue/singleline-html-element-content-newline': 'off', |
||||
|
'vue/attribute-hyphenation': 'off', |
||||
|
'vue/require-default-prop': 'off', |
||||
|
'vue/multi-word-component-names': [ |
||||
|
'error', |
||||
|
{ |
||||
|
ignores: ['index'], //需要忽略的组件名 |
||||
|
}, |
||||
|
], |
||||
|
'vue/html-self-closing': [ |
||||
|
'error', |
||||
|
{ |
||||
|
html: { |
||||
|
void: 'always', |
||||
|
normal: 'never', |
||||
|
component: 'always', |
||||
|
}, |
||||
|
svg: 'always', |
||||
|
math: 'always', |
||||
|
}, |
||||
|
], |
||||
|
// Enable vue/script-setup-uses-vars rule |
||||
|
'vue/script-setup-uses-vars': 'error', |
||||
|
}, |
||||
|
}; |
||||
@ -0,0 +1,7 @@ |
|||||
|
node_modules |
||||
|
.DS_Store |
||||
|
**/.DS_Store |
||||
|
dist |
||||
|
dist-ssr |
||||
|
*.local |
||||
|
.idea |
||||
@ -0,0 +1,30 @@ |
|||||
|
/* |
||||
|
* 代码格式化配置 |
||||
|
* |
||||
|
* @Author: 1024创新实验室-主任:卓大 |
||||
|
* @Date: 2022-09-12 14:44:18 |
||||
|
* @Wechat: zhuda1024 |
||||
|
* @Email: lab1024@163.com |
||||
|
* @Copyright 1024创新实验室 ( https://1024lab.net ),Since 2012 |
||||
|
*/ |
||||
|
module.exports = { |
||||
|
printWidth: 150, // 每行代码长度(默认80) |
||||
|
tabWidth: 2, // 缩进空格数 |
||||
|
useTabs: false, //不用tab缩进 |
||||
|
semi: true, //// 在语句末尾打印分号 |
||||
|
singleQuote: true, // 使用单引号而不是双引号 |
||||
|
vueIndentScriptAndStyle: true, //Vue文件脚本和样式标签缩进 |
||||
|
quoteProps: 'as-needed', // 更改引用对象属性的时间 可选值"<as-needed|consistent|preserve>" |
||||
|
jsxSingleQuote: true, // 在JSX中使用单引号而不是双引号 |
||||
|
trailingComma: 'es5', //多行时尽可能打印尾随逗号。(例如,单行数组永远不会出现逗号结尾。) 可选值"<none|es5|all>",默认none |
||||
|
bracketSpacing: true, // 在对象文字中的括号之间打印空格 |
||||
|
jsxBracketSameLine: false, //jsx 标签的反尖括号需要换行 |
||||
|
arrowParens: 'always', // 在单独的箭头函数参数周围包括括号 always:(x) => x \ avoid:x => x |
||||
|
rangeStart: 0, // 这两个选项可用于格式化以给定字符偏移量(分别包括和不包括)开始和结束的代码 |
||||
|
rangeEnd: Infinity, |
||||
|
requirePragma: false, // 指定要使用的解析器,不需要写文件开头的 @prettier |
||||
|
insertPragma: false, // 不需要自动在文件开头插入 @prettier |
||||
|
proseWrap: 'preserve', // 使用默认的折行标准 always\never\preserve |
||||
|
htmlWhitespaceSensitivity: 'css', // 指定HTML文件的全局空格敏感度 css\strict\ignore |
||||
|
endOfLine: 'auto', // 因为prettier的规范和eslint的换行规则不同,所以这个必须配置。要不然每次打开文件都会有一堆的警告;换行符使用 lf 结尾是 可选值"<auto|lf|crlf|cr |
||||
|
}; |
||||
@ -0,0 +1,3 @@ |
|||||
|
/dist/* |
||||
|
/public/* |
||||
|
public/* |
||||
@ -0,0 +1,70 @@ |
|||||
|
module.exports = { |
||||
|
root: true, |
||||
|
plugins: ['stylelint-order'], |
||||
|
extends: ['stylelint-config-standard', 'stylelint-config-prettier'], |
||||
|
rules: { |
||||
|
'selector-pseudo-class-no-unknown': [ |
||||
|
true, |
||||
|
{ |
||||
|
ignorePseudoClasses: ['global'], |
||||
|
}, |
||||
|
], |
||||
|
'selector-pseudo-element-no-unknown': [ |
||||
|
true, |
||||
|
{ |
||||
|
ignorePseudoElements: ['v-deep'], |
||||
|
}, |
||||
|
], |
||||
|
'at-rule-no-unknown': [ |
||||
|
true, |
||||
|
{ |
||||
|
ignoreAtRules: [ |
||||
|
'tailwind', |
||||
|
'apply', |
||||
|
'variants', |
||||
|
'responsive', |
||||
|
'screen', |
||||
|
'function', |
||||
|
'if', |
||||
|
'each', |
||||
|
'include', |
||||
|
'mixin', |
||||
|
], |
||||
|
}, |
||||
|
], |
||||
|
'no-empty-source': null, |
||||
|
'named-grid-areas-no-invalid': null, |
||||
|
'unicode-bom': 'never', |
||||
|
'no-descending-specificity': null, |
||||
|
'font-family-no-missing-generic-family-keyword': null, |
||||
|
'declaration-colon-space-after': 'always-single-line', |
||||
|
'declaration-colon-space-before': 'never', |
||||
|
// 'declaration-block-trailing-semicolon': 'always',
|
||||
|
'rule-empty-line-before': [ |
||||
|
'always', |
||||
|
{ |
||||
|
ignore: ['after-comment', 'first-nested'], |
||||
|
}, |
||||
|
], |
||||
|
'unit-no-unknown': [true, { ignoreUnits: ['rpx'] }], |
||||
|
'order/order': [ |
||||
|
[ |
||||
|
'dollar-variables', |
||||
|
'custom-properties', |
||||
|
'at-rules', |
||||
|
'declarations', |
||||
|
{ |
||||
|
type: 'at-rule', |
||||
|
name: 'supports', |
||||
|
}, |
||||
|
{ |
||||
|
type: 'at-rule', |
||||
|
name: 'media', |
||||
|
}, |
||||
|
'rules', |
||||
|
], |
||||
|
{ severity: 'warning' }, |
||||
|
], |
||||
|
}, |
||||
|
ignoreFiles: ['**/*.js', '**/*.jsx', '**/*.tsx', '**/*.ts'], |
||||
|
}; |
||||
@ -0,0 +1,3 @@ |
|||||
|
{ |
||||
|
"search.useGlobalIgnoreFiles": true |
||||
|
} |
||||
@ -0,0 +1,235 @@ |
|||||
|
<!-- |
||||
|
* 季度统计组件 |
||||
|
* |
||||
|
* @Author: wzh |
||||
|
* @Date: 2025-12-24 14:44:06 |
||||
|
* @Copyright 1.0 |
||||
|
--> |
||||
|
<template> |
||||
|
<div class="quarter-statistics"> |
||||
|
<!-- 查询表单 --> |
||||
|
<a-card title="查询条件" size="small" class="query-card"> |
||||
|
<a-form :model="queryForm" layout="inline"> |
||||
|
<a-form-item label="季度"> |
||||
|
<a-select v-model:value="queryForm.quarter" placeholder="请选择季度" style="width: 120px"> |
||||
|
<a-select-option v-for="quarter in quarterOptions" :key="quarter.value" :value="quarter.value"> |
||||
|
{{ quarter.label }} |
||||
|
</a-select-option> |
||||
|
</a-select> |
||||
|
</a-form-item> |
||||
|
|
||||
|
<a-form-item label="年度"> |
||||
|
<a-select v-model:value="queryForm.year" placeholder="请选择年度" style="width: 120px"> |
||||
|
<a-select-option v-for="year in yearOptions" :key="year" :value="year"> |
||||
|
{{ year }}年 |
||||
|
</a-select-option> |
||||
|
</a-select> |
||||
|
</a-form-item> |
||||
|
|
||||
|
<a-form-item label="律师姓名"> |
||||
|
<a-input v-model:value="queryForm.lawyerName" placeholder="请输入律师姓名" style="width: 150px" /> |
||||
|
</a-form-item> |
||||
|
|
||||
|
<a-form-item label="律所名称"> |
||||
|
<a-input v-model:value="queryForm.firmName" placeholder="请输入律所名称" style="width: 150px" /> |
||||
|
</a-form-item> |
||||
|
|
||||
|
<a-form-item> |
||||
|
<a-button type="primary" @click="handleSearch"> |
||||
|
<SearchOutlined /> |
||||
|
查询 |
||||
|
</a-button> |
||||
|
<a-button @click="handleReset" style="margin-left: 8px"> |
||||
|
<ReloadOutlined /> |
||||
|
重置 |
||||
|
</a-button> |
||||
|
<a-button @click="handleExport" type="primary" style="margin-left: 8px"> |
||||
|
<ExportOutlined /> |
||||
|
导出Excel |
||||
|
</a-button> |
||||
|
</a-form-item> |
||||
|
</a-form> |
||||
|
</a-card> |
||||
|
|
||||
|
<!-- 统计表格 --> |
||||
|
<a-card title="季度服务统计" size="small" class="table-card"> |
||||
|
<a-table |
||||
|
:columns="columns" |
||||
|
:dataSource="tableData" |
||||
|
:pagination="pagination" |
||||
|
:loading="loading" |
||||
|
size="small" |
||||
|
bordered |
||||
|
> |
||||
|
<template #bodyCell="{ column, record }"> |
||||
|
<template v-if="column.dataIndex === 'quarterDuration'"> |
||||
|
{{ record.quarterDuration }} 小时 |
||||
|
</template> |
||||
|
<template v-else-if="column.dataIndex === 'quarterCost'"> |
||||
|
{{ record.quarterCost }} 元 |
||||
|
</template> |
||||
|
<template v-else-if="column.dataIndex === 'yearDuration'"> |
||||
|
{{ record.yearDuration }} 小时 |
||||
|
</template> |
||||
|
<template v-else-if="column.dataIndex === 'yearCost'"> |
||||
|
{{ record.yearCost }} 元 |
||||
|
</template> |
||||
|
</template> |
||||
|
</a-table> |
||||
|
</a-card> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script setup> |
||||
|
import { ref, reactive, onMounted } from 'vue'; |
||||
|
import { SearchOutlined, ReloadOutlined, ExportOutlined } from '@ant-design/icons-vue'; |
||||
|
import { message } from 'ant-design-vue'; |
||||
|
import { serviceApplicationsApi } from '/@/api/business/service-applications/service-applications-api'; |
||||
|
|
||||
|
// 查询表单 |
||||
|
const queryForm = reactive({ |
||||
|
quarter: undefined, |
||||
|
year: new Date().getFullYear(), |
||||
|
lawyerName: '', |
||||
|
firmName: '' |
||||
|
}); |
||||
|
|
||||
|
// 季度选项 |
||||
|
const quarterOptions = [ |
||||
|
{ label: '第一季度', value: 1 }, |
||||
|
{ label: '第二季度', value: 2 }, |
||||
|
{ label: '第三季度', value: 3 }, |
||||
|
{ label: '第四季度', value: 4 } |
||||
|
]; |
||||
|
|
||||
|
// 年度选项(近5年) |
||||
|
const yearOptions = ref([]); |
||||
|
|
||||
|
// 表格列定义 |
||||
|
const columns = [ |
||||
|
{ |
||||
|
title: '执业律师姓名', |
||||
|
dataIndex: 'lawyerName', |
||||
|
key: 'lawyerName', |
||||
|
width: 120 |
||||
|
}, |
||||
|
{ |
||||
|
title: '执业证号', |
||||
|
dataIndex: 'certificateNumber', |
||||
|
key: 'certificateNumber', |
||||
|
width: 120 |
||||
|
}, |
||||
|
{ |
||||
|
title: '季度累计服务时长', |
||||
|
dataIndex: 'quarterDuration', |
||||
|
key: 'quarterDuration', |
||||
|
width: 120 |
||||
|
}, |
||||
|
{ |
||||
|
title: '季度累计服务成本', |
||||
|
dataIndex: 'quarterCost', |
||||
|
key: 'quarterCost', |
||||
|
width: 120 |
||||
|
}, |
||||
|
{ |
||||
|
title: '年度累计服务时长', |
||||
|
dataIndex: 'yearDuration', |
||||
|
key: 'yearDuration', |
||||
|
width: 120 |
||||
|
}, |
||||
|
{ |
||||
|
title: '年度累计服务成本', |
||||
|
dataIndex: 'yearCost', |
||||
|
key: 'yearCost', |
||||
|
width: 120 |
||||
|
} |
||||
|
]; |
||||
|
|
||||
|
const tableData = ref([]); |
||||
|
const loading = ref(false); |
||||
|
const pagination = reactive({ |
||||
|
current: 1, |
||||
|
pageSize: 10, |
||||
|
total: 0, |
||||
|
showSizeChanger: true, |
||||
|
showQuickJumper: true, |
||||
|
showTotal: (total) => `共 ${total} 条` |
||||
|
}); |
||||
|
|
||||
|
// 初始化年度选项 |
||||
|
function initYearOptions() { |
||||
|
const currentYear = new Date().getFullYear(); |
||||
|
for (let i = currentYear; i >= currentYear - 4; i--) { |
||||
|
yearOptions.value.push(i); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 查询数据 |
||||
|
async function handleSearch() { |
||||
|
loading.value = true; |
||||
|
try { |
||||
|
const params = { |
||||
|
...queryForm, |
||||
|
pageNum: pagination.current, |
||||
|
pageSize: pagination.pageSize |
||||
|
}; |
||||
|
|
||||
|
// 调用API获取季度统计数据 |
||||
|
const result = await serviceApplicationsApi.getQuarterStatistics(params); |
||||
|
|
||||
|
if (result.data) { |
||||
|
tableData.value = result.data.list || []; |
||||
|
pagination.total = result.data.total || 0; |
||||
|
} |
||||
|
} catch (error) { |
||||
|
message.error('查询失败'); |
||||
|
console.error(error); |
||||
|
} finally { |
||||
|
loading.value = false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 重置查询条件 |
||||
|
function handleReset() { |
||||
|
Object.assign(queryForm, { |
||||
|
quarter: undefined, |
||||
|
year: new Date().getFullYear(), |
||||
|
lawyerName: '', |
||||
|
firmName: '' |
||||
|
}); |
||||
|
handleSearch(); |
||||
|
} |
||||
|
|
||||
|
// 导出Excel |
||||
|
function handleExport() { |
||||
|
message.info('导出功能开发中...'); |
||||
|
// 这里调用导出API |
||||
|
// await serviceApplicationsApi.exportQuarterStatistics(queryForm); |
||||
|
} |
||||
|
|
||||
|
// 分页变化 |
||||
|
function handleTableChange(pag) { |
||||
|
pagination.current = pag.current; |
||||
|
pagination.pageSize = pag.pageSize; |
||||
|
handleSearch(); |
||||
|
} |
||||
|
|
||||
|
onMounted(() => { |
||||
|
initYearOptions(); |
||||
|
handleSearch(); |
||||
|
}); |
||||
|
</script> |
||||
|
|
||||
|
<style scoped> |
||||
|
.quarter-statistics { |
||||
|
padding: 0; |
||||
|
} |
||||
|
|
||||
|
.query-card { |
||||
|
margin-bottom: 16px; |
||||
|
} |
||||
|
|
||||
|
.table-card { |
||||
|
margin-bottom: 0; |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,30 @@ |
|||||
|
<!-- |
||||
|
* 服务申报统计 |
||||
|
* |
||||
|
* @Author: wzh |
||||
|
* @Date: 2025-12-24 14:44:06 |
||||
|
* @Copyright 1.0 |
||||
|
--> |
||||
|
<template> |
||||
|
<div class="service-application-count"> |
||||
|
<a-tabs v-model:activeKey="activeTab" type="card"> |
||||
|
<!-- 季度统计 --> |
||||
|
<a-tab-pane key="quarter" tab="季度统计"> |
||||
|
<QuarterStatistics /> |
||||
|
</a-tab-pane> |
||||
|
</a-tabs> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script setup> |
||||
|
import { ref } from 'vue'; |
||||
|
import QuarterStatistics from '/@/components/system/service-count/quarter-statistics.vue'; |
||||
|
const activeTab = ref('quarter'); |
||||
|
</script> |
||||
|
|
||||
|
<style scoped> |
||||
|
.service-application-count { |
||||
|
padding: 16px; |
||||
|
background: #fff; |
||||
|
} |
||||
|
</style> |
||||
Loading…
Reference in new issue