report template initial

This commit is contained in:
郑茂强 2018-09-18 10:03:59 +08:00
commit 091bc916cf
27 changed files with 16314 additions and 0 deletions

3
.browserslistrc Normal file
View File

@ -0,0 +1,3 @@
> 1%
last 2 versions
not ie <= 8

21
.gitignore vendored Normal file
View File

@ -0,0 +1,21 @@
.DS_Store
node_modules
/dist
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw*

5
.postcssrc.js Normal file
View File

@ -0,0 +1,5 @@
module.exports = {
plugins: {
autoprefixer: {}
}
}

4
.prettierrc Normal file
View File

@ -0,0 +1,4 @@
{
"singleQuote": true,
"trailingComma": "all"
}

26
README.md Normal file
View File

@ -0,0 +1,26 @@
# table-summary
## Project setup
```
npm install
```
### Compiles and hot-reloads for development
```
npm run serve
```
### Compiles and minifies for production
```
npm run build
```
### Lints and fixes files
```
npm run lint
```
### Run your unit tests
```
npm run test:unit
```

5
babel.config.js Normal file
View File

@ -0,0 +1,5 @@
module.exports = {
presets: [
'@vue/app'
]
}

25
jest.config.js Normal file
View File

@ -0,0 +1,25 @@
module.exports = {
moduleFileExtensions: [
'js',
'jsx',
'json',
'vue',
'ts',
'tsx'
],
transform: {
'^.+\\.vue$': 'vue-jest',
'.+\\.(css|styl|less|sass|scss|png|jpg|ttf|woff|woff2)$': 'jest-transform-stub',
'^.+\\.tsx?$': 'ts-jest'
},
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1'
},
snapshotSerializers: [
'jest-serializer-vue'
],
testMatch: [
'**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)'
],
testURL: 'http://localhost/'
}

15631
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

36
package.json Normal file
View File

@ -0,0 +1,36 @@
{
"name": "table-summary",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint",
"test:unit": "vue-cli-service test:unit"
},
"dependencies": {
"@types/html2canvas": "0.0.33",
"@types/jspdf": "^1.1.31",
"abab": "^2.0.0",
"html2canvas": "^1.0.0-alpha.12",
"jspdf": "^1.4.1",
"vue": "^2.5.17",
"vue-class-component": "^6.0.0",
"vue-property-decorator": "^7.0.0",
"vue-router": "^3.0.1"
},
"devDependencies": {
"@types/jest": "^23.1.4",
"@vue/cli-plugin-babel": "^3.0.0",
"@vue/cli-plugin-typescript": "^3.0.0",
"@vue/cli-plugin-unit-jest": "^3.0.0",
"@vue/cli-service": "^3.0.0",
"@vue/test-utils": "^1.0.0-beta.20",
"babel-core": "7.0.0-bridge.0",
"node-sass": "^4.9.0",
"sass-loader": "^7.0.1",
"ts-jest": "^23.0.0",
"typescript": "^3.0.0",
"vue-template-compiler": "^2.5.17"
}
}

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

17
public/index.html Normal file
View File

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title>table-summary</title>
</head>
<body>
<noscript>
<strong>We're sorry but table-summary doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>

14
src/App.vue Normal file
View File

@ -0,0 +1,14 @@
<template>
<div id="app">
<router-view/>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({});
</script>
<style lang="scss">
</style>

108
src/assets/data.ts Normal file
View File

@ -0,0 +1,108 @@
const data = {
orderNo: '101808023922',
clientName: 'SongQingyang3',
soldData: '2018-08-23',
contactName: 'K01',
contactNo: '12345678901',
deliveryAddress: 'D01',
addOn: '测试PTP-G刀偏置',
boards: [
{
id: 1234,
matierial: '颗粒板',
color: '暖白',
boardInfos: [
{
houseName: 'F01',
closetName: 'F01',
boardNo: 'B1816478862',
boardName: '背板',
length: 944,
width: 59,
thickness: 18,
quantity: 1,
area: 0.568,
mutation: '',
shape: '',
direction: '1/1/1/1 ',
strip: '正纹',
addOn: '',
},
{
houseName: 'F01',
closetName: 'F01',
boardNo: 'B1816478862',
boardName: '层板',
length: 944,
width: 598,
thickness: 18,
quantity: 1,
area: 0.568,
mutation: '',
shape: '造型',
direction: '1/1/1/1 ',
strip: '正纹',
addOn: '',
},
{
houseName: 'F01',
closetName: 'F01',
boardNo: 'B1816478875',
boardName: '右侧板',
length: 1198,
width: 548,
thickness: 18,
quantity: 1,
area: 0.66,
mutation: '',
shape: '造型',
direction: '1/1/1/1 ',
strip: '正纹',
addOn: '',
},
],
},
{
id: 1235,
matierial: '生态板 ',
color: '暖白',
boardInfos: [
{
houseName: 'F01',
closetName: 'F01',
boardNo: 'B1816478862',
boardName: '背板',
length: 944,
width: 598,
thickness: 18,
quantity: 1,
area: 0.568,
mutation: '',
shape: '',
direction: '1/1/1/1 ',
strip: '正纹',
addOn: '',
},
{
houseName: 'F01',
closetName: 'F01',
boardNo: 'B1816478861',
boardName: '背板',
length: 944,
width: 598,
thickness: 18,
quantity: 1,
area: 0.568,
mutation: '',
shape: '',
direction: '1/1/1/1 ',
strip: '正纹',
addOn: '',
},
],
},
],
};
export default data;

BIN
src/assets/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

56
src/components/pdf.vue Normal file
View File

@ -0,0 +1,56 @@
<template>
<div class='pdf'>
<button @click="createPdf">print PDF</button>
<button @click="createExcel">print EXCEL</button>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import jsPDF from 'jspdf';
import html2canvas from 'html2canvas';
export default Vue.extend({
data() {
return {
canvasUrl: '' as string,
};
},
methods: {
createPdf() {
const elements: any = document.getElementById('order-details');
html2canvas(elements, {
scale: 2,
}).then((canvas: any) => {
canvas.setAttribute('id', 'canvas');
document.body.appendChild(canvas);
const canvasElement: any = document.getElementById('canvas');
this.canvasUrl = canvasElement.toDataURL();
const doc = new jsPDF({
unit: 'cm',
});
const canvasHeight = canvasElement.style.height.replace('px', '');
const height = canvasHeight / window.outerHeight;
doc.addImage(this.canvasUrl, 'JPEG', 0.5, 0.5, 20, 29 * height);
doc.save('test' + '.pdf');
});
const canvasElementToRemove: any = document.getElementById('canvas');
canvasElementToRemove.remove();
},
createExcel() {
const tabs = document.getElementsByTagName('table');
let allElementText: any;
for (const tab of tabs) {
let tabText: string = '<table border="2px"><tr>';
for (const row of tab.rows) {
tabText += row.innerHTML + '</tr>';
}
allElementText += tabText + '</table>';
}
window.open(
'data:application/vnd.ms-excel,' + encodeURIComponent(allElementText),
);
},
},
});
</script>

View File

@ -0,0 +1,165 @@
<template>
<div class='main'>
<div class='content'>
<table>
<tr v-for="row in rows" :key="row.rowId" :cells="row.cells" v-bind:class="{active:row.rowId==selectedRow}">
<input type="button" :value='row.rowId' @click="rowClickHandler(row.rowId)">
<reportCell v-for="cell in row.cells" :cell="cell" v-on:cellIdFromChild="getCellFromChildren" :key="cell.cellId"></reportCell>
</tr>
</table>
</div>
<div class='side'>
<div class='row-tool'>
<button @click="addRow">添加行</button>
<button @click="deleteRow">删除行</button>
</div>
<div class='td-tool'>
<button @click="addCell(selectedRow)">添加列</button>
<button @click="deleteCell(selectedCell)">删除列</button>
</div>
<div>
<label>表头:</label><input type="text" v-model="inputTitle"></div>
<button @click="submitInput">确定</button>
{{infos}}
</div>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import reportCell from './reportCell.vue';
const infosFormat: Array<{
rowId: string;
cells: Array<{ cellId: number; title: string }>;
}> = [
{
rowId: '行0',
cells: [
{ cellId: 1, title: '列1' },
{ cellId: 2, title: '列2' },
{ cellId: 3, title: '列3' },
{ cellId: 4, title: '列4' },
{ cellId: 5, title: '列5' },
{ cellId: 6, title: '列6' },
{ cellId: 7, title: '列7' },
{ cellId: 8, title: '列8' },
{ cellId: 9, title: '列9' },
{ cellId: 10, title: '列10' },
{ cellId: 11, title: '列11' },
{ cellId: 12, title: '列12' },
],
},
];
const selectedRowFormat: string = '';
const selectedCellFormat: number = 0;
const inputTitleFormat: string = '';
let rowId = 0;
let cellId = 9000;
export default Vue.extend({
components: { reportCell },
data() {
return {
infos: infosFormat,
selectedRow: selectedRowFormat,
selectedCell: selectedCellFormat,
inputTitle: inputTitleFormat,
};
},
computed: {
rows(): Array<{
rowId: string;
cells: Array<{ cellId: number; title: string }>;
}> {
return this.infos;
},
},
methods: {
getCellFromChildren(cell: { cellId: number; title: string }): void {
this.selectedCell = cell.cellId;
this.inputTitle = cell.title;
},
addRow() {
this.infos.push({
rowId: '行' + (rowId += 1),
cells: [],
});
},
deleteRow() {
this.infos = this.infos.filter(item => item.rowId !== this.selectedRow);
},
addCell(id: string) {
for (const row of this.infos) {
if (id === row.rowId) {
row.cells.push({ cellId: (cellId += 1), title: '列' + cellId });
}
}
},
deleteCell(id: number) {
for (const row of this.infos) {
for (const cell in row.cells) {
if (row.cells[cell].cellId === id) {
row.cells.splice(Number(cell), 1);
}
}
}
},
submitInput() {
for (const row of this.infos) {
for (const cellIndex in row.cells) {
if (row.cells[cellIndex].cellId === this.selectedCell) {
row.cells.splice(Number(cellIndex), 1, {
title: this.inputTitle,
cellId: this.selectedCell.toString(),
});
}
}
}
},
rowClickHandler(id: string): void {
this.selectedRow = id;
},
},
});
</script>
<style lang="scss" scoped>
.main {
display: flex;
flex-wrap: wrap;
height: 100%;
.content {
width: 70%;
}
.side {
background-color: lightgray;
height: 300px;
width: 30%;
}
}
table {
border: 1px black solid;
width: 100%;
table-layout: fixed;
text-align: center;
td {
width: 8.3%;
}
}
.active {
width: 100%;
background-color: blue;
}
</style>
/*
row.cells.splice(cell, 1, {
cellId: 666,
title: this.inputTitle,
});
*/

View File

@ -0,0 +1,21 @@
<template>
<td colspan="2" v-on:click="$emit('cellIdFromChild',cell)">{{title}} </td>
</template>
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({
props: ['cell'],
data() {
return {
title: this.cell.title,
};
},
methods: {},
});
</script>
<style lang="scss" scoped>
td {
border: 1px black solid;
}
</style>

View File

@ -0,0 +1,40 @@
<template>
<tr @click="rowClickHandler" :class="{active:isActive}">
<reportCell></reportCell>
</tr>
</template>
<script lang="ts">
import Vue from 'vue';
import reportCell from './reportCell.vue';
export default Vue.extend({
props: ['rowId'],
components: { reportCell },
data: function() {
return {
isActive: false,
};
},
methods: {
rowClickHandler: function() {
this.isActive = !this.isActive;
console.log(this.rowId);
},
},
});
</script>
<style lang="scss" scoped>
tr {
border: 1px black solid;
}
.active {
background-color: blue;
}
</style>
/*
@click="rowClickHandler(row.rowId,$event)" v-bind:class="{active:row.rowId==selectedRow}"
*/

10
src/main.ts Normal file
View File

@ -0,0 +1,10 @@
import Vue from 'vue';
import App from './App.vue';
import router from './router';
Vue.config.productionTip = false;
new Vue({
router,
render: (h) => h(App),
}).$mount('#app');

16
src/router.ts Normal file
View File

@ -0,0 +1,16 @@
import Vue from 'vue';
import Router from 'vue-router';
import ReportTemplate from './components/reportTemplate/ReportTemplate.vue';
Vue.use(Router);
export default new Router({
routes: [
{
path: '/',
name: 'ReportTemplate',
component: ReportTemplate,
},
],
});

13
src/shims-tsx.d.ts vendored Normal file
View File

@ -0,0 +1,13 @@
import Vue, { VNode } from 'vue';
declare global {
namespace JSX {
// tslint:disable no-empty-interface
interface Element extends VNode {}
// tslint:disable no-empty-interface
interface ElementClass extends Vue {}
interface IntrinsicElements {
[elem: string]: any;
}
}
}

4
src/shims-vue.d.ts vendored Normal file
View File

@ -0,0 +1,4 @@
declare module '*.vue' {
import Vue from 'vue';
export default Vue;
}

5
src/views/About.vue Normal file
View File

@ -0,0 +1,5 @@
<template>
<div class="about">
<h1>This is an about page</h1>
</div>
</template>

18
src/views/Home.vue Normal file
View File

@ -0,0 +1,18 @@
<template>
<div class="home">
<img alt="Vue logo" src="../assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js + TypeScript App"/>
</div>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import HelloWorld from '@/components/HelloWorld.vue'; // @ is an alias to /src
@Component({
components: {
HelloWorld,
},
})
export default class Home extends Vue {}
</script>

View File

@ -0,0 +1,12 @@
import { shallowMount } from '@vue/test-utils';
import HelloWorld from '@/components/HelloWorld.vue';
describe('HelloWorld.vue', () => {
it('renders props.msg when passed', () => {
const msg = 'new message';
const wrapper = shallowMount(HelloWorld, {
propsData: { msg },
});
expect(wrapper.text()).toMatch(msg);
});
});

40
tsconfig.json Normal file
View File

@ -0,0 +1,40 @@
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"strict": true,
"jsx": "preserve",
"importHelpers": true,
"moduleResolution": "node",
"experimentalDecorators": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"sourceMap": true,
"baseUrl": ".",
"types": [
"node",
"jest"
],
"paths": {
"@/*": [
"src/*"
]
},
"lib": [
"esnext",
"dom",
"dom.iterable",
"scripthost"
]
},
"include": [
"src/**/*.ts",
"src/**/*.tsx",
"src/**/*.vue",
"tests/**/*.ts",
"tests/**/*.tsx"
],
"exclude": [
"node_modules"
]
}

19
tslint.json Normal file
View File

@ -0,0 +1,19 @@
{
"defaultSeverity": "warning",
"extends": [
"tslint:recommended"
],
"linterOptions": {
"exclude": [
"node_modules/**"
]
},
"rules": {
"quotemark": [true, "single"],
"indent": [true, "spaces", 2],
"interface-name": false,
"ordered-imports": false,
"object-literal-sort-keys": false,
"no-consecutive-blank-lines": false
}
}