Commit 32fa130e by 严立

v1.0.0

parents
Showing with 4278 additions and 0 deletions
{
"presets": [
["env", {
"modules": false,
"targets": {
"browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
}
}],
"stage-2"
],
"plugins": ["transform-vue-jsx", "transform-runtime"]
}
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 4
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
.DS_Store
node_modules/
/dist/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
// https://github.com/michael-ciniawsky/postcss-load-config
module.exports = {
"plugins": {
"postcss-import": {},
"postcss-url": {},
// to edit target browsers: use "browserslist" field in package.json
"autoprefixer": {}
}
}
# merchant2.1.x
> A Vue.js project
## Build Setup
``` bash
# install dependencies
npm install
# serve with hot reload at localhost:8080
npm run dev
# build for production with minification
npm run build
# build for production and view the bundle analyzer report
npm run build --report
```
For a detailed explanation on how things work, check out the [guide](http://vuejs-templates.github.io/webpack/) and [docs for vue-loader](http://vuejs.github.io/vue-loader).
'use strict'
require('./check-versions')()
process.env.NODE_ENV = 'production'
const ora = require('ora')
const rm = require('rimraf')
const path = require('path')
const chalk = require('chalk')
const webpack = require('webpack')
const config = require('../config')
const webpackConfig = require('./webpack.prod.conf')
const spinner = ora('building for production...')
spinner.start()
rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
if (err) throw err
webpack(webpackConfig, (err, stats) => {
spinner.stop()
if (err) throw err
process.stdout.write(stats.toString({
colors: true,
modules: false,
children: false, // If you are using ts-loader, setting this to true will make TypeScript errors show up during build.
chunks: false,
chunkModules: false
}) + '\n\n')
if (stats.hasErrors()) {
console.log(chalk.red(' Build failed with errors.\n'))
process.exit(1)
}
console.log(chalk.cyan(' Build complete.\n'))
console.log(chalk.yellow(
' Tip: built files are meant to be served over an HTTP server.\n' +
' Opening index.html over file:// won\'t work.\n'
))
})
})
'use strict'
const chalk = require('chalk')
const semver = require('semver')
const packageConfig = require('../package.json')
const shell = require('shelljs')
function exec (cmd) {
return require('child_process').execSync(cmd).toString().trim()
}
const versionRequirements = [
{
name: 'node',
currentVersion: semver.clean(process.version),
versionRequirement: packageConfig.engines.node
}
]
if (shell.which('npm')) {
versionRequirements.push({
name: 'npm',
currentVersion: exec('npm --version'),
versionRequirement: packageConfig.engines.npm
})
}
module.exports = function () {
const warnings = []
for (let i = 0; i < versionRequirements.length; i++) {
const mod = versionRequirements[i]
if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) {
warnings.push(mod.name + ': ' +
chalk.red(mod.currentVersion) + ' should be ' +
chalk.green(mod.versionRequirement)
)
}
}
if (warnings.length) {
console.log('')
console.log(chalk.yellow('To use this template, you must update following to modules:'))
console.log()
for (let i = 0; i < warnings.length; i++) {
const warning = warnings[i]
console.log(' ' + warning)
}
console.log()
process.exit(1)
}
}
'use strict'
const path = require('path')
const config = require('../config')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const packageConfig = require('../package.json')
exports.assetsPath = function (_path) {
const assetsSubDirectory = process.env.NODE_ENV === 'production'
? config.build.assetsSubDirectory
: config.dev.assetsSubDirectory
return path.posix.join(assetsSubDirectory, _path)
}
exports.cssLoaders = function (options) {
options = options || {}
const cssLoader = {
loader: 'css-loader',
options: {
sourceMap: options.sourceMap
}
}
const postcssLoader = {
loader: 'postcss-loader',
options: {
sourceMap: options.sourceMap
}
}
// generate loader string to be used with extract text plugin
function generateLoaders (loader, loaderOptions) {
const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader]
if (loader) {
loaders.push({
loader: loader + '-loader',
options: Object.assign({}, loaderOptions, {
sourceMap: options.sourceMap
})
})
}
// Extract CSS when that option is specified
// (which is the case during production build)
if (options.extract) {
return ExtractTextPlugin.extract({
use: loaders,
fallback: 'vue-style-loader'
})
} else {
return ['vue-style-loader'].concat(loaders)
}
}
// https://vue-loader.vuejs.org/en/configurations/extract-css.html
return {
css: generateLoaders(),
postcss: generateLoaders(),
less: generateLoaders('less').concat({
loader: 'sass-resources-loader',
options: {
resources: path.resolve(__dirname, '../src/common/css/global.less')
}
}),
sass: generateLoaders('sass', { indentedSyntax: true }),
scss: generateLoaders('sass'),
stylus: generateLoaders('stylus'),
styl: generateLoaders('stylus')
}
}
// Generate loaders for standalone style files (outside of .vue)
exports.styleLoaders = function (options) {
const output = []
const loaders = exports.cssLoaders(options)
for (const extension in loaders) {
const loader = loaders[extension]
output.push({
test: new RegExp('\\.' + extension + '$'),
use: loader
})
}
return output
}
exports.createNotifierCallback = () => {
const notifier = require('node-notifier')
return (severity, errors) => {
if (severity !== 'error') return
const error = errors[0]
const filename = error.file && error.file.split('!').pop()
notifier.notify({
title: packageConfig.name,
message: severity + ': ' + error.name,
subtitle: filename || '',
icon: path.join(__dirname, 'logo.png')
})
}
}
'use strict'
const utils = require('./utils')
const config = require('../config')
const isProduction = process.env.NODE_ENV === 'production'
const sourceMapEnabled = isProduction
? config.build.productionSourceMap
: config.dev.cssSourceMap
module.exports = {
loaders: utils.cssLoaders({
sourceMap: sourceMapEnabled,
extract: isProduction
}),
cssSourceMap: sourceMapEnabled,
cacheBusting: config.dev.cacheBusting,
transformToRequire: {
video: ['src', 'poster'],
source: 'src',
img: 'src',
image: 'xlink:href'
}
}
'use strict'
const path = require('path')
const utils = require('./utils')
const config = require('../config')
const vueLoaderConfig = require('./vue-loader.conf')
function resolve (dir) {
return path.join(__dirname, '..', dir)
}
module.exports = {
context: path.resolve(__dirname, '../'),
entry: {
app: './src/main.js'
},
output: {
path: config.build.assetsRoot,
filename: '[name].js',
publicPath: process.env.NODE_ENV === 'production'
? config.build.assetsPublicPath
: config.dev.assetsPublicPath
},
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'@': resolve('src'),
}
},
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: vueLoaderConfig
},
{
test: /\.js$/,
loader: 'babel-loader',
include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('img/[name].[hash:7].[ext]')
}
},
{
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('media/[name].[hash:7].[ext]')
}
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
}
}
]
},
node: {
// prevent webpack from injecting useless setImmediate polyfill because Vue
// source contains it (although only uses it if it's native).
setImmediate: false,
// prevent webpack from injecting mocks to Node native modules
// that does not make sense for the client
dgram: 'empty',
fs: 'empty',
net: 'empty',
tls: 'empty',
child_process: 'empty'
}
}
'use strict'
const utils = require('./utils')
const webpack = require('webpack')
const config = require('../config')
const merge = require('webpack-merge')
const path = require('path')
const baseWebpackConfig = require('./webpack.base.conf')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
const portfinder = require('portfinder')
const HOST = process.env.HOST
const PORT = process.env.PORT && Number(process.env.PORT)
const devWebpackConfig = merge(baseWebpackConfig, {
module: {
rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true })
},
// cheap-module-eval-source-map is faster for development
devtool: config.dev.devtool,
// these devServer options should be customized in /config/index.js
devServer: {
clientLogLevel: 'warning',
historyApiFallback: {
rewrites: [
{ from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, 'index.html') },
],
},
hot: true,
contentBase: false, // since we use CopyWebpackPlugin.
compress: true,
host: HOST || config.dev.host,
port: PORT || config.dev.port,
open: config.dev.autoOpenBrowser,
overlay: config.dev.errorOverlay
? { warnings: false, errors: true }
: false,
publicPath: config.dev.assetsPublicPath,
proxy: config.dev.proxyTable,
quiet: true, // necessary for FriendlyErrorsPlugin
watchOptions: {
poll: config.dev.poll,
}
},
plugins: [
new webpack.DefinePlugin({
'process.env': require('../config/dev.env')
}),
new webpack.HotModuleReplacementPlugin(),
new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update.
new webpack.NoEmitOnErrorsPlugin(),
// https://github.com/ampedandwired/html-webpack-plugin
new HtmlWebpackPlugin({
filename: 'index.html',
template: 'index.html',
inject: true
}),
// copy custom static assets
new CopyWebpackPlugin([
{
from: path.resolve(__dirname, '../static'),
to: config.dev.assetsSubDirectory,
ignore: ['.*']
}
])
]
})
module.exports = new Promise((resolve, reject) => {
portfinder.basePort = process.env.PORT || config.dev.port
portfinder.getPort((err, port) => {
if (err) {
reject(err)
} else {
// publish the new Port, necessary for e2e tests
process.env.PORT = port
// add port to devServer config
devWebpackConfig.devServer.port = port
// Add FriendlyErrorsPlugin
devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({
compilationSuccessInfo: {
messages: [`Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`],
},
onErrors: config.dev.notifyOnErrors
? utils.createNotifierCallback()
: undefined
}))
resolve(devWebpackConfig)
}
})
})
'use strict'
const path = require('path')
const utils = require('./utils')
const webpack = require('webpack')
const config = require('../config')
const merge = require('webpack-merge')
const baseWebpackConfig = require('./webpack.base.conf')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
const env = require('../config/prod.env')
const webpackConfig = merge(baseWebpackConfig, {
module: {
rules: utils.styleLoaders({
sourceMap: config.build.productionSourceMap,
extract: true,
usePostCSS: true
})
},
devtool: config.build.productionSourceMap ? config.build.devtool : false,
output: {
path: config.build.assetsRoot,
filename: utils.assetsPath('js/[name].[chunkhash].js'),
chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
},
plugins: [
// http://vuejs.github.io/vue-loader/en/workflow/production.html
new webpack.DefinePlugin({
'process.env': env
}),
new UglifyJsPlugin({
uglifyOptions: {
compress: {
warnings: false
}
},
sourceMap: config.build.productionSourceMap,
parallel: true
}),
// extract css into its own file
new ExtractTextPlugin({
filename: utils.assetsPath('css/[name].[contenthash].css'),
// Setting the following option to `false` will not extract CSS from codesplit chunks.
// Their CSS will instead be inserted dynamically with style-loader when the codesplit chunk has been loaded by webpack.
// It's currently set to `true` because we are seeing that sourcemaps are included in the codesplit bundle as well when it's `false`,
// increasing file size: https://github.com/vuejs-templates/webpack/issues/1110
allChunks: true,
}),
// Compress extracted CSS. We are using this plugin so that possible
// duplicated CSS from different components can be deduped.
new OptimizeCSSPlugin({
cssProcessorOptions: config.build.productionSourceMap
? { safe: true, map: { inline: false } }
: { safe: true }
}),
// generate dist index.html with correct asset hash for caching.
// you can customize output by editing /index.html
// see https://github.com/ampedandwired/html-webpack-plugin
new HtmlWebpackPlugin({
filename: config.build.index,
template: 'index.html',
inject: true,
minify: {
removeComments: true,
collapseWhitespace: true,
removeAttributeQuotes: true
// more options:
// https://github.com/kangax/html-minifier#options-quick-reference
},
// necessary to consistently work with multiple chunks via CommonsChunkPlugin
chunksSortMode: 'dependency'
}),
// keep module.id stable when vendor modules does not change
new webpack.HashedModuleIdsPlugin(),
// enable scope hoisting
new webpack.optimize.ModuleConcatenationPlugin(),
// split vendor js into its own file
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks (module) {
// any required modules inside node_modules are extracted to vendor
return (
module.resource &&
/\.js$/.test(module.resource) &&
module.resource.indexOf(
path.join(__dirname, '../node_modules')
) === 0
)
}
}),
// extract webpack runtime and module manifest to its own file in order to
// prevent vendor hash from being updated whenever app bundle is updated
new webpack.optimize.CommonsChunkPlugin({
name: 'manifest',
minChunks: Infinity
}),
// This instance extracts shared chunks from code splitted chunks and bundles them
// in a separate chunk, similar to the vendor chunk
// see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk
new webpack.optimize.CommonsChunkPlugin({
name: 'app',
async: 'vendor-async',
children: true,
minChunks: 3
}),
// copy custom static assets
new CopyWebpackPlugin([
{
from: path.resolve(__dirname, '../static'),
to: config.build.assetsSubDirectory,
ignore: ['.*']
}
])
]
})
if (config.build.productionGzip) {
const CompressionWebpackPlugin = require('compression-webpack-plugin')
webpackConfig.plugins.push(
new CompressionWebpackPlugin({
asset: '[path].gz[query]',
algorithm: 'gzip',
test: new RegExp(
'\\.(' +
config.build.productionGzipExtensions.join('|') +
')$'
),
threshold: 10240,
minRatio: 0.8
})
)
}
if (config.build.bundleAnalyzerReport) {
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
webpackConfig.plugins.push(new BundleAnalyzerPlugin())
}
module.exports = webpackConfig
'use strict'
const merge = require('webpack-merge')
const prodEnv = require('./prod.env')
module.exports = merge(prodEnv, {
NODE_ENV: '"development"'
})
'use strict'
// Template version: 1.3.1
// see http://vuejs-templates.github.io/webpack for documentation.
const path = require('path')
module.exports = {
dev: {
// Paths
assetsSubDirectory: 'static',
assetsPublicPath: '/',
proxyTable: {
'/api': {
target: 'http://192.168.31.231:8084',//设置你调用的接口域名和端口号 别忘了加http
changeOrigin: true,
pathRewrite: {
// '^/api': '' //这里理解成用‘/api’代替target里面的地址,后面组件中我们掉接口时直接用api代替 比如我要调用'https://api.douban.com/user/add',直接写‘/api/user/add’即可,此处的‘api’可以设置为自己想要设置的任何词语,符合规范即可
}
}
},
// Various Dev Server settings
host: 'localhost', // can be overwritten by process.env.HOST
port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
autoOpenBrowser: false,
errorOverlay: true,
notifyOnErrors: true,
poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-
/**
* Source Maps
*/
// https://webpack.js.org/configuration/devtool/#development
devtool: 'cheap-module-eval-source-map',
// If you have problems debugging vue-files in devtools,
// set this to false - it *may* help
// https://vue-loader.vuejs.org/en/options.html#cachebusting
cacheBusting: true,
cssSourceMap: true
},
build: {
// Template for index.html
index: path.resolve(__dirname, '../dist/index.html'),
// Paths
assetsRoot: path.resolve(__dirname, '../dist'),
assetsSubDirectory: 'static',
assetsPublicPath: '/',
/**
* Source Maps
*/
productionSourceMap: true,
// https://webpack.js.org/configuration/devtool/#production
devtool: '#source-map',
// Gzip off by default as many popular static hosts such as
// Surge or Netlify already gzip all static assets for you.
// Before setting to `true`, make sure to:
// npm install --save-dev compression-webpack-plugin
productionGzip: false,
productionGzipExtensions: ['js', 'css'],
// Run the build command with an extra argument to
// View the bundle analyzer report after build finishes:
// `npm run build --report`
// Set to `true` or `false` to always turn it on or off
bundleAnalyzerReport: process.env.npm_config_report
}
}
'use strict'
module.exports = {
NODE_ENV: '"production"'
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>厦门建发招标采购平台</title>
</head>
<body>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
This diff could not be displayed because it is too large.
{
"name": "merchant2.1.x",
"version": "1.0.0",
"description": "A Vue.js project",
"author": "立 <236048639@qq.com>",
"private": true,
"scripts": {
"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
"start": "npm run dev",
"build": "node build/build.js"
},
"dependencies": {
"miment": "0.0.9",
"vue": "^2.5.2",
"vue-router": "^3.0.1"
},
"devDependencies": {
"autoprefixer": "^7.1.2",
"babel-core": "^6.22.1",
"babel-helper-vue-jsx-merge-props": "^2.0.3",
"babel-loader": "^7.1.1",
"babel-plugin-syntax-jsx": "^6.18.0",
"babel-plugin-transform-runtime": "^6.22.0",
"babel-plugin-transform-vue-jsx": "^3.5.0",
"babel-preset-env": "^1.3.2",
"babel-preset-stage-2": "^6.22.0",
"chalk": "^2.0.1",
"copy-webpack-plugin": "^4.0.1",
"css-loader": "^0.28.0",
"element-ui": "^2.13.1",
"extract-text-webpack-plugin": "^3.0.0",
"file-loader": "^1.1.4",
"font-spider": "^1.3.5",
"friendly-errors-webpack-plugin": "^1.6.1",
"html-webpack-plugin": "^2.30.1",
"js-base64": "^2.5.2",
"less": "^3.11.1",
"less-loader": "^4.1.0",
"node-notifier": "^5.1.2",
"optimize-css-assets-webpack-plugin": "^3.2.0",
"ora": "^1.2.0",
"portfinder": "^1.0.13",
"postcss-import": "^11.0.0",
"postcss-loader": "^2.0.8",
"postcss-url": "^7.2.1",
"rimraf": "^2.6.0",
"sass-resources-loader": "^2.0.3",
"semver": "^5.3.0",
"shelljs": "^0.7.6",
"uglifyjs-webpack-plugin": "^1.1.1",
"url-loader": "^0.5.8",
"vue-baidu-map": "^0.21.22",
"vue-cli-plugin-style-resources-loader": "^0.1.4",
"vue-loader": "^13.3.0",
"vue-style-loader": "^3.0.1",
"vue-template-compiler": "^2.5.2",
"vuex": "^3.4.0",
"webpack": "^3.6.0",
"webpack-bundle-analyzer": "^2.9.0",
"webpack-dev-server": "^2.9.1",
"webpack-merge": "^4.1.0"
},
"engines": {
"node": ">= 6.0.0",
"npm": ">= 3.0.0"
},
"browserslist": [
"> 1%",
"last 2 versions",
"not ie <= 8"
]
}
<template>
<div id="app">
<router-view></router-view>
</div>
</template>
<script>
export default {
data: function () {
return {
}
}
}
</script>
<style lang="less">
#app {
display: flex;
min-width: 1200px;
flex-direction: column;
align-items: center;
background: #F8F8F8;
}
</style>
\ No newline at end of file
No preview for this file type
/* SAMCSS-layout */
.row {
display: flex;
flex-direction: row;
}
.col {
display: flex;
flex-direction: column;
}
.con-s {
justify-content: flex-start;
}
.con-c {
justify-content: center;
}
.con-e {
justify-content: flex-end;
}
.con-b {
justify-content: space-between;
}
.con-a {
justify-content: space-around;
}
.align-s {
align-items: flex-start;
}
.align-c {
align-items: center;
}
.align-e {
align-items: flex-end;
}
\ No newline at end of file
@maxWidth: 1200px;
@fontSizeBase: 12;
@fontSizeMultiple: 2;
@fontSize00: @fontSizeBase + @fontSizeMultiple * 0px; // 12px
@fontSize01: @fontSizeBase + @fontSizeMultiple * 1px; // 14px
@fontSize02: @fontSizeBase + @fontSizeMultiple * 2px; // 16px
@fontSize03: @fontSizeBase + @fontSizeMultiple * 3px; // 18px
@fontSize04: @fontSizeBase + @fontSizeMultiple * 4px; // 20px
@fontSize06: @fontSizeBase + @fontSizeMultiple * 6px; // 24px
@fontSize07: @fontSizeBase + @fontSizeMultiple * 7px; // 26px
@fontSize08: @fontSizeBase + @fontSizeMultiple * 8px; // 28px
@fontSize09: @fontSizeBase + @fontSizeMultiple * 9px; // 30px
@fontSize10: @fontSizeBase + @fontSizeMultiple * 10px; // 32px
@colorGrey00: #000000;
@colorGrey10: #1A1A1A;
@colorGrey20: #333333;
@colorGrey30: #4D4D4D;
@colorGrey40: #666666;
@colorGrey50: #808080;
@colorGrey60: #999999;
@colorGrey70: #B3B3B3;
@colorGrey80: #CCCCCC;
@colorGrey90: #E5E5E5;
@colorRed: #CF2F1D;
@colorBlue: #2575FA;
@colorGreen: #49B939;
@colorWhite: #FFFFFF;
@colorYellow: #EBA947;
@backgroundImageUrl: '~@/assets/bg-06.png';
// 页面正文宽度
.global-maxwidth {
width: @maxWidth;
max-width: @maxWidth;
}
// 单行文本超出省略
.global-overflow-ellipsis {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.global-color-red { color: @colorRed; }
.global-color-blue { color: @colorBlue; }
.global-color-grey { color: @colorGrey60; }
.global-color-green { color: @colorGreen; }
.global-color-white { color: @colorWhite; }
.global-color-yellow { color: @colorYellow; }
// 禁用文本样式
.global-disable-font {
color: @colorGrey60 !important;
}
// 禁用背景样式
.global-disable {
background: @colorGrey60 !important;
}
// 置灰背景样式
.global-enable {
background: @colorBlue !important;
}
// 选中文本样式
.global-enable-font {
color: @colorBlue !important;
}
.global-none {
display: none !important;
}
.global-cursor {
cursor: pointer;
}
.global-hover:hover {
color: @colorBlue;
}
.global-routine-button {
width: 160px;
height: 52px;
margin: 0 40px !important;
border-radius: 26px;
border: 1px @colorBlue solid !important;
color: @colorBlue !important;
background: @colorWhite !important;
}
.global-routine-button:focus,
.global-routine-button:hover {
border: 1px @colorBlue solid !important;
color: @colorBlue !important;
background: @colorWhite !important;
}
.global-enable-button {
width: 160px;
height: 52px;
margin: 0 40px !important;
border-radius: 26px;
border: 1px @colorBlue solid !important;
color: @colorWhite !important;
background: @colorBlue !important;
}
.global-enable-button:focus,
.global-enable-button:hover {
border: 1px @colorBlue solid !important;
color: @colorWhite !important;
background: @colorBlue !important;
}
.global-disable-button {
width: 160px;
height: 52px;
margin: 0 40px !important;
border-radius: 26px;
border: 1px @colorGrey50 solid !important;
color: @colorWhite !important;
background: @colorGrey50 !important;
}
.global-disable-button:focus,
.global-disable-button:hover {
border: 1px @colorGrey50 solid !important;
color: @colorWhite !important;
background: @colorGrey50 !important;
}
// element-ui 自定样式
//按钮组件
.el-button:hover {
color: #000000;
border-color: #dcdfe6;
background-color: #ffffff;
}
// 文件上传组件清除渐变动画
.el-upload-list__item {
transition: none !important;
}
// 分页组件
.el-pagination {
display: flex;
flex-direction: row;
align-items: center;
.btn-prev,
.btn-next {
display: none;
}
> span {
display: inline-block;
height: 46px !important;
}
> span:nth-child(1) {
padding-top: 8px;
font-size: @fontSize02;
}
> span:nth-child(2) {
width: 136px;
height: 46px;
font-size: @fontSize02;
div,
input {
width: 136px;
height: 46px;
margin: 0 !important;
padding: 0 !important;
}
span {
font-size: @fontSize02;
}
.el-input__inner {
border: none;
font-size: @fontSize02 !important;
background: #f6f6f9;
}
}
.el-pager {
display: flex;
flex-direction: row;
.active {
color: #FFFFFF;
background: #CF2F1D !important;
}
.more,
.number {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
width: 46px;
height: 46px;
margin: 0 4px;
padding: 0;
font-size: @fontSize02;
font-weight: 500;
}
.number {
background: #f6f6f9;
}
}
> span:nth-child(6) {
width: 130px;
font-size: @fontSize02;
.el-input {
margin: 0 8px 0 12px;
}
.el-input__inner {
width: 46px;
height: 46px;
font-size: @fontSize02;
}
}
}
\ No newline at end of file
/*声明 WebFont*/
@font-face {
font-family: 'siyuanyahei';
src: url('../../assets/NotoSansHans-Light.otf');
font-weight: normal;
font-style: normal;
}
html,body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
font-family: 'siyuanyahei', arial;
box-sizing: border-box !important;
margin: 0;
padding: 0;
}
input,
input:focus,
input:hover {
outline: none !important;
border-color: #dcdfe6 !important;
}
li {
list-style-type: none;
}
button {
outline: none !important;
}
\ No newline at end of file
let output = function (funcValue, funcType, funcUpdateObject) {
switch (funcType) {
case 'size':
funcUpdateObject.size = funcValue
break
case 'total':
funcUpdateObject.total = funcValue
break
case 'current':
funcUpdateObject.current = funcValue
break
}
console.log('[frame pagination]: ', JSON.stringify(funcUpdateObject))
}
export default output
\ No newline at end of file
let output = {
// 配置后台公告字典标识映射
// 避免后台更变数值影响逻辑
// - 全部
// 0 - 竞价报价
// 1 - 竞价结果
// 2 - 招标采购
// 3 - 资格预审
// 4 - 变更澄清
// 5 - 中标候选
// 6 - 招标结果
// 9 - 其他公告
noticeType: {
raw: ['', 1, 2, 5, 3, 4, 7, 8, 6],
mapping: ['', 2, 3, 4, 5, 6, 0, 1, 9],
}
}
export default output
\ No newline at end of file
let output = {
/**
* 重新渲染表格
* 修复 element-ui table 不会跟随屏幕宽度自适应的问题
* @function
* @returns
*/
tableRender: function (funcVue, funcContainerWidth, funcTableItemWidth, funcTableItemWidthProportion) {
let funcWidth = 0
if (document.body.clientHeight > document.documentElement.clientHeight) {
funcWidth = funcContainerWidth / 100
} else {
funcWidth = (funcContainerWidth - 17) / 100
}
for (let i = 0, len = funcTableItemWidth.length; i < len; i++) {
funcTableItemWidth[i] = Math.floor(funcTableItemWidthProportion[i] * funcWidth)
}
funcVue.tableShow = true
},
}
export default output
\ No newline at end of file
let output = {
// 开发路径
base: 'http://bid-server.meiqicloud.com/',
agentSignIn: 'http://bid-vue.meiqicloud.com/'
// 正式路径
// base: '/Api/',
// agentSignIn: 'http://bid-vue.meiqicloud.com/'
}
output.uploadFile = output.base + 'bid/common/webupload/upload'
export default output
\ No newline at end of file
let output = {
sendType: 'json', // 数据发送方式
sendTypeEnumeration: [ 'params', 'json','form', 'formdata'],
method: 'post', // 请求方式
methodEnumeration: [ 'get', 'post' ],
timeout: 10000, // 超时设置
isToken: true, // 是否携带
isLog: true, // 是否打印请求相关信息
errorCode: [ 101 ],
}
export default output
\ No newline at end of file
let output = function (funcParams, funcType) {
funcType = funcType.toLowerCase()
switch (funcType) {
case 'url':
if (JSON.stringify(funcParams) !== '{}') {
let funcQuery = '?'
Object.keys(funcParams).forEach((funcKey) => {
funcQuery = funcQuery + funcKey + '=' + funcParams[funcKey] + '&'
})
return funcQuery.substring(0, funcQuery.length - 1)
} else {
return ''
}
break
case 'json':
return JSON.stringify(funcParams)
break
case 'formdata':
let funcFormData = new FormData()
Object.keys(funcParams).forEach((funcKey) => {
funcFormData.append(funcKey, funcParams[funcKey])
})
return funcFormData
break
}
}
export default output
\ No newline at end of file
let output = function (funcXMLHttpRequest, funcConfigure) {
switch (funcConfigure.sendType) {
case 'json':
funcXMLHttpRequest.setRequestHeader('Content-Type', 'application/json;')
break
case 'file':
funcXMLHttpRequest.setRequestHeader('Content-Type', 'multipart/form-data;')
break
case 'form':
funcXMLHttpRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded;')
break
case 'formdata':
// 浏览器自行设置表头
break
case 'params':
break
}
}
export default output
\ No newline at end of file
import iVue from '../../../main.js'
import iHost from '../host.js'
let timerClose = 0
let loading = null
let loadingFilter = [
'bid/order/queryState', // 查询支付状态
'bid/common/getImgCode', // 获取图片验证
]
let output = {
/**
* 请求拦截器
* @function
* @param {object} funcConfigure - 请求配置
* @returns {boolean}
*/
request: function (funXmlHttpRequest, funcConfigure, funcUrl) {
funcUrl = funcUrl.replace(iHost.base, '')
// 只有不被过滤的接口才会显示加载动画
if (loadingFilter.indexOf(funcUrl) === -1) {
if (loading === null) {
loading = iVue.$loading({ lock: false, text: 'Loading', spinner: 'el-icon-loading', background: 'rgba(255, 255, 255, 0.7)' })
}
if (timerClose !== 0) {
clearTimeout(timerClose)
}
}
// 默认添加 token 属性
if (funcConfigure.isToken) {
funXmlHttpRequest.setRequestHeader('token', localStorage.getItem('token'))
}
},
/**
* 响应拦截器
* @function
* @param {object} funcConfigure - 请求配置
* @param {object} funcResult - 响应数据
* @returns {boolean}
*/
response: function (funcConfigure, funcResult) {
if (loading) {
timerClose = setTimeout(() => {
if (loading) {
loading.close()
}
loading = null
clearTimeout(timerClose)
}, 500)
}
let funcDataType = ''
try {
JSON.parse(funcResult)
funcDataType = 'object'
}
catch (funcError) {
funcDataType = 'other'
}
if (funcDataType === 'object') {
// console.log('api: ', funcConfigure.url)
// console.log('par: ', JSON.parse(funcConfigure.data))
// console.log('res: ')
// console.log(JSON.parse(funcResult))
// console.log('■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■')
let funcResultData = JSON.parse(funcResult)
switch (Number(funcResultData.code)) {
case 10001:
console.log('token overdue')
this.$store.commit('isSignIn', false)
this.$store.commit('redirectPath', null)
localStorage.clear()
iVue.$router.push('/')
return false
break
// 请求正常直接返回 data 内容
case 200:
return { state: true, response: funcResultData.data}
break
// 请求异常返回 msg 错误提示
default:
return { state: false, response: { message: funcResultData.msg }}
break
}
} else {
// console.log('api: ', funcConfigure.url)
// console.log('par: ', JSON.parse(funcConfigure.data))
// console.log('res: ')
// console.log(funcResult)
// console.log('■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■')
}
return funcResult
}
}
export default output
import iHeader from './header.js'
import iDataform from './dataform.js'
import iConfigure from './configure.js'
import iInterceptors from './interceptors.js'
let output = {
/**
* 通用请求函数
* @function
* @param {string} funcUrl - 完整请求路径
* @param {object} funcData - 请求数据
* @param {string} funcType - 请求数据类型
* @param {string} funcMethod - 请求方法
* @param {object} funcOther - 其他配置
*/
request: function (funcUrl, funcData, funcSendType, funcMethod, funcOther) {
// 获取默认请求设置
let funcConfigure = JSON.parse(JSON.stringify(iConfigure))
Object.assign(funcConfigure, funcOther)
// 检查数据发放方式有效性
if (funcSendType && iConfigure.sendTypeEnumeration.indexOf(funcSendType.toLowerCase()) >= 0) {
funcConfigure.sendType = funcSendType.toLowerCase()
}
// 检查请求方法字段有效性
if (funcMethod && iConfigure.methodEnumeration.indexOf(funcMethod) >= 0) {
funcConfigure.method = funcMethod
}
// get 请求需要将参数转换为 url 形式
if (funcConfigure.method === 'get') {
// 设置数据类型
funcData = iDataform(funcData, 'url')
let funcPromise = new Promise(function (funcResolve, funcReject) {
let funcXMLHttpRequest = new XMLHttpRequest()
funcXMLHttpRequest.timeout = funcConfigure.timeout
funcXMLHttpRequest.open(funcConfigure.method, funcUrl + funcData, true)
// 请求之前修改
iHeader(funcXMLHttpRequest, funcConfigure)
iInterceptors.request(funcXMLHttpRequest, funcConfigure, funcUrl)
funcXMLHttpRequest.send()
funcXMLHttpRequest.onreadystatechange = function () {
if (funcXMLHttpRequest.readyState !== 4) {
return
}
let funStatus = funcXMLHttpRequest.status
if ((funStatus >= 200 && funStatus < 300) || funStatus === 304) {
try {
let funcInterceptorsResponse = iInterceptors.response(funcConfigure, funcXMLHttpRequest.responseText)
if (funcInterceptorsResponse.state) {
funcResolve(funcInterceptorsResponse.response)
} else {
funcReject(funcInterceptorsResponse.response)
}
} catch (funError) {
funcReject(funError)
}
} else {
let funcResponse = iInterceptors.response(funcConfigure, funcXMLHttpRequest.responseText)
funcReject(funcResponse.response)
}
}
})
return funcPromise
}
if (funcConfigure.method === 'post') {
// 设置数据类型
funcData = iDataform(funcData, funcConfigure.sendType)
let funcPromise = new Promise(function (funcResolve, funcReject) {
let funcXMLHttpRequest = new XMLHttpRequest()
funcXMLHttpRequest.timeout = funcConfigure.timeout
funcXMLHttpRequest.open(funcConfigure.method, funcUrl, true)
// 请求之前修改
iHeader(funcXMLHttpRequest, funcConfigure)
iInterceptors.request(funcXMLHttpRequest, funcConfigure, funcUrl)
funcXMLHttpRequest.send(funcData)
funcXMLHttpRequest.onreadystatechange = function () {
if (funcXMLHttpRequest.readyState !== 4) {
return
}
let funStatus = funcXMLHttpRequest.status
if ((funStatus >= 200 && funStatus < 300) || funStatus === 304) {
try {
let funcInterceptorsResponse = iInterceptors.response(funcConfigure, funcXMLHttpRequest.responseText)
if (funcInterceptorsResponse.state) {
funcResolve(funcInterceptorsResponse.response)
} else {
funcReject(funcInterceptorsResponse.response)
}
} catch (funError) {
funcReject(funError)
}
} else {
let funcResponse = iInterceptors.response(funcConfigure, funcXMLHttpRequest.responseText)
funcReject(funcResponse.response)
}
}
})
return funcPromise
}
},
get: function () {
},
post: function () {
},
}
export default output
\ No newline at end of file
let output = {
isMoney: function (value) {
let regExp = new RegExp('^(([1-9][0-9]*\.[0-9][0-9]*)|([0]\.[0-9][0-9]*)|([1-9][0-9]*)|([0]{1}))$')
return regExp.test(value)
},
isChinese: function (value) {
let regExp = new RegExp('[\u4e00-\u9fa5]+', 'ig')
return regExp.test(value)
},
isPhone: function (value) {
let regExp = new RegExp(/^(13[0-9]|14[5|7]|15[0|1|2|3|4|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9]|19[0-9])[0-9]{8}$/, 'ig')
return regExp.test(value)
},
isFixedPhone: function (value) {
let regExp = new RegExp(/^\d{3}-\d{7,8}|\d{4}-\d{7,8}$/, 'ig')
return regExp.test(value)
}
}
export default output
\ No newline at end of file
import iAtom from './atom.js'
let output = {
// 文本,除emoji符号
predefineRoutineText: function (funcRule, funcValue, funcCallback) {
let funcRegExp = new RegExp(/[\uD83C[\uDF00-\uDFFF]|\uD83D[\uDC00-\uDE4F]|\uD83D[\uDE80-\uDEFF]|[\u2700-\u27BF]\uFE0F]/, 'ig')
if (funcRegExp.test(funcValue)) {
funcCallback(new Error('不允许使用表情符号'))
return
}
funcCallback()
},
// 文本,仅数字、英文字母(区分大小写)
predefineNumeralText: function (funcRule, funcValue, funcCallback) {
let funcRegExp = new RegExp(/^[0-9a-z]+$/, 'ig')
if (!funcRegExp.test(funcValue)) {
funcCallback(new Error(funcRule.message))
return
}
funcCallback()
},
// 文本,仅数字
predefineNumeral: function (funcRule, funcValue, funcCallback) {
let funcRegExp = new RegExp(/^[0-9]+$/, 'ig')
if (!funcRegExp.test(funcValue)) {
funcCallback(new Error(funcRule.message))
return
}
funcCallback()
},
email: function (funcRule, funcValue, funcCallback) {
let funcRegExp = new RegExp(/^[A-Za-z0-9\u4e00-\u9fa5]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/, 'ig')
if (!funcRegExp.test(funcValue)) {
funcCallback(new Error(funcRule.message))
return
}
funcCallback()
},
idCard: function (funcRule, funcValue, funcCallback) {
let funcRegExp = new RegExp(/^[1-9][0-9]{5}(18|19|20)[0-9]{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)[0-9]{3}[0-9Xx]$/, 'ig')
if (!funcRegExp.test(funcValue)) {
funcCallback(new Error(funcRule.message))
return
}
funcCallback()
},
phone: function (funcRule, funcValue, funcCallback) {
let funcRegExp = new RegExp(/^(13[0-9]|14[5|7]|15[0|1|2|3|4|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9]|19[0-9])[0-9]{8}$/, 'ig')
if (!funcRegExp.test(funcValue)) {
funcCallback(new Error(funcRule.message))
return
}
funcCallback()
},
fixedPhone: function (funcRule, funcValue, funcCallback) {
let funcRegExp = new RegExp(/^[0-9*#-]+$/, 'ig')
if (!funcRegExp.test(funcValue)) {
funcCallback(new Error(funcRule.message))
return
}
funcCallback()
},
phoneAndFixedPhone: function (funcRule, funcValue, funcCallback) {
if (!iAtom.isPhone(funcValue) && !iAtom.isFixedPhone(funcValue)) {
funcCallback(new Error(funcRule.message))
return
}
funcCallback()
},
password: function (funcRule, funcValue, funcCallback) {
let funcCombinedStrength = 0
// 是否包含数字
let funcRegExp = new RegExp(/[0-9]+/, 'ig')
if (funcRegExp.test(funcValue)) {
funcCombinedStrength = funcCombinedStrength + 1
}
// 是否包含字母
funcRegExp = new RegExp(/[a-z]+/, 'ig')
if (funcRegExp.test(funcValue)) {
funcCombinedStrength = funcCombinedStrength + 1
}
// 是否包含特殊符号
funcRegExp = new RegExp(/(?=[\x21-\x7e]+)[^a-z0-9]+/, 'ig')
if (funcRegExp.test(funcValue)) {
funcCombinedStrength = funcCombinedStrength + 1
}
// 组合强度验证
if (funcCombinedStrength < 2) {
funcCallback(new Error(funcRule.message))
return
}
funcCallback()
},
passwordRepeat: function (funcRule, funcValue, funcCallback, funcPassword) {
if (funcValue !== funcPassword) {
funcCallback(new Error(funcRule.message))
return
}
funcCallback()
},
unEmoji: function (funcRule, funcValue, funcCallback) {
let funcRegExp = new RegExp(/[\uD83C|\uD83D|\uD83E][\uDC00-\uDFFF][\u200D|\uFE0F]|[\uD83C|\uD83D|\uD83E][\uDC00-\uDFFF]|[0-9|*|#]\uFE0F\u20E3|[0-9|#]\u20E3|[\u203C-\u3299]\uFE0F\u200D|[\u203C-\u3299]\uFE0F|[\u2122-\u2B55]|\u303D|[\A9|\AE]\u3030|\uA9|\uAE|\u3030/, 'ig')
if (funcRegExp.test(funcValue)) {
funcCallback(new Error(funcRule.message))
return
}
funcCallback()
},
unSpace: function (funcRule, funcValue, funcCallback) {
let funcRegExp = new RegExp(/ /, 'ig')
if (funcRegExp.test(funcValue)) {
funcCallback(new Error(funcRule.message))
return
}
funcCallback()
},
unChinese: function (rule, value, callback) {
let regExp = new RegExp('[\u4e00-\u9fa5]+', 'ig')
regExp.test(value) ? callback(new Error(rule.message)) : callback()
},
}
export default output
\ No newline at end of file
let output = function () {
return new Date()
// return 1590564000000
// return 1590654903000 // 2020-05-28 16:35:03
// return 1591778103000 // 2020-06-10 16:35:03
// return 1592469303000 // 2020-06-18 16:35:03
// return 1592728503000 // 2020-06-21 16:35:03
}
export default output
\ No newline at end of file
import iBase64 from 'js-base64';
let output = {
/**
* 提取令牌有效期限
* @function
* @param {event}
* @returns
*/
term: function (funcToken) {
let funcIndex = funcToken.indexOf('.') + 1
let funcDateBase = funcToken.substring(funcIndex)
funcIndex = funcDateBase.indexOf('.')
funcDateBase = funcDateBase.substring(0, funcIndex)
let funcDateInfo = iBase64.Base64.decode(funcDateBase)
let funcDateKey = '"exp":'
let funcDateString = funcDateInfo.substring(funcDateInfo.indexOf(funcDateKey) + funcDateKey.length, funcDateInfo.length)
funcDateString = funcDateString.substring(0, funcDateString.indexOf(','))
return Number(funcDateString)
},
/**
* 根据时间判断当前令牌状态
* @function
* @param {string} - funcToken
* @returns
*/
state: function (funcToken) {
let funcDate = output.term(funcToken)
let funcNowDate = Math.round(new Date() / 1000)
if (funcNowDate < funcDate) {
// 判断当前时间是否小于令牌期限
if (funcNowDate + 3600 < funcDate) {
// 令牌有效时间大于安全时间
return 'valid'
} else {
return 'refresh'
}
} else {
// 当前令牌过期需要重新登录
return 'invalid'
}
},
}
export default output
\ No newline at end of file
<template>
<!-- 通用组件 - 省市区选择器 -->
<div class="components-area row">
<el-select v-model="areaSelect" placeholder="请选择" value-key="index" @change="(item) => { onSelect('area', item) }">
<el-option v-for="item in area" :key="item" :label="item" :value="item"></el-option>
</el-select>
<span>-</span>
<el-select v-model="citySelect" placeholder="请选择" value-key="index" @change="(item) => { onSelect('city', item) }">
<el-option v-for="item in city" :key="item" :label="item" :value="item"></el-option>
</el-select>
<span>-</span>
<el-select v-model="countySelect" placeholder="请选择" value-key="index" @change="(item) => { onSelect('county', item) }">
<el-option v-for="item in county" :key="item" :label="item" :value="item"></el-option>
</el-select>
</div>
</template>
<script>
import iArea from '@/common/js/area.js'
export default {
data () {
return {
area: [],
areaIndex: 0,
areaSelect: '',
city: [],
cityIndex: 0,
citySelect: '',
county: [],
countyIndex: 0,
countySelect: '',
areaData: iArea,
}
},
created: function () {
this.setArea()
this.setCity()
this.setCounty()
this.initSelect()
},
methods: {
/**
* 设置初始数据
* @function
* @returns
*/
initSelect: function () {
if (this.$store.getters.areaSelection.length === 0) {
this.$emit('change', [this.areaSelect, this.citySelect, this.countySelect])
} else {
this.setSelect(this.$store.getters.areaSelection)
}
},
setArea: function () {
let funcData = this.areaData
this.area = []
for (let i = 0, len = funcData.length; i < len; i++) {
this.area.push(funcData[i].name)
}
this.areaSelect = this.area[0]
},
setCity: function () {
let funcData = this.areaData[this.areaIndex].city
this.city = []
for (let i = 0, len = funcData.length; i < len; i++) {
this.city.push(funcData[i].name)
}
this.citySelect = this.city[0]
},
setCounty: function () {
this.county = this.areaData[this.areaIndex].city[this.cityIndex].county
this.countySelect = this.county[0]
},
/**
* 设置地域选择
* @function
* @param {array } funcSelection - ['省份', '城市', '区域' ]
* @returns
*/
setSelect: function (funcSelection) {
let funcAreaSelection = this.$store.getters.areaSelection
for (let i = 0, len = this.area.length; i < len; i++) {
if (this.area[i] === funcAreaSelection[0]) {
this.areaIndex = i
this.areaSelect = funcAreaSelection[0]
break
}
}
this.setCity()
for (let i = 0, len = this.city.length; i < len; i++) {
if (this.city[i] === funcAreaSelection[1]) {
this.cityIndex = i
this.citySelect = funcAreaSelection[1]
break
}
}
this.setCounty()
for (let i = 0, len = this.county.length; i < len; i++) {
if (this.county[i] === funcAreaSelection[2]) {
this.countyIndex = i
this.countySelect = funcAreaSelection[2]
break
}
}
},
/**
* 选择地域
* @function
* @param {array } funcArea
* @param {array } funcItem
* @returns
*/
onSelect: function (funcArea, funcItem) {
let funcData
switch (funcArea) {
case 'area':
funcData = this.areaData
for (let i = 0, len = funcData.length; i < len; i++) {
if (funcItem === funcData[i].name) {
this.areaIndex = i
this.cityIndex = 0
this.countyIndex = 0
break
}
}
this.setCity()
this.setCounty()
break
case 'city':
funcData = this.areaData[this.areaIndex].city
for (let i = 0, len = funcData.length; i < len; i++) {
if (funcItem === funcData[i].name) {
this.cityIndex = i
this.countyIndex = 0
break
}
}
this.setCounty()
break
case 'county':
this.countyIndex = this.areaData[this.areaIndex].city[this.cityIndex].county.indexOf(funcItem)
break
}
this.$emit('change', [this.areaSelect, this.citySelect, this.countySelect])
},
}
}
</script>
<style lang="less">
.components-area {
.el-select {
width: 110px;
height: 40px;
margin-right: 4px;
}
> span {
margin: 0 8px;
}
}
</style>
<template>
<!-- 通用组件 - 底部 -->
<div class="components-footer col align-c">
<div class="line"></div>
<div class="global-maxwidth row con-b align-s">
<div class="company-info">
<div class="logo">
<el-image :src="imageLogo" fit="fit"></el-image>
</div>
<div>
<p>地址:厦门市思明区吕岭路1733号创想中心1801单元</p>
<p>联系电话:0592-5859311</p>
</div>
</div>
<div class="other-link row">
<div class="other-link-item">
<span>采购服务</span>
<span>发布招标</span>
<span>供应商入驻</span>
<span>政策法规招标</span>
</div>
<div class="other-link-item">
<span>供应商服务</span>
<span>供应商入驻</span>
<span>招标公告</span>
<span>竞价招标</span>
</div>
<div class="other-link-item">
<span>招标资讯</span>
<span @click="$router.push('/policy')">政策法规</span>
<span @click="$router.push('/trends')">招标动态</span>
</div>
<div class="other-link-item">
<span>特色服务</span>
<span @click="$router.push('/question')">在线咨询</span>
<span><a href="https://banyan.xmhy.ltd/" target="view_window">法律服务</a></span>
</div>
</div>
<div class="follow-us col">
<div class="other-link-item row con-c">
<span>关注我们</span>
</div>
<el-image :src="imageCode" fit="fit"></el-image>
</div>
</div>
<div class="record-info global-maxwidth row con-c align-c">
<span>©2020</span>
<span>建信发展(厦门)采购招标有限公司</span>
<span>备案号:闽ICP备05001567</span>
</div>
</div>
</template>
<script>
import iImageLogo from '../assets/logo@2x.png'
import iImageCode from '../assets/code.png'
export default {
name: 'componentsFooter',
data () {
return {
imageLogo: iImageLogo,
imageCode: iImageCode,
}
}
}
</script>
<style lang="less">
.components-footer {
width: 100%;
height: 260px;
background-image: url('~@/assets/bg-05.png');
.line {
width: 100%;
height: 4px;
margin-bottom: 48px;
background-image: linear-gradient(90deg, #00468C, #CF2F1D);
}
.company-info {
flex-grow: 1;
font-size: @fontSize01;
color: #666666;
p {
margin-top: 10px;
}
.logo {
margin-bottom: 16px;
img {
width: 350px;
height: 40px;
}
}
}
.other-link {
min-height: 168px;
.other-link-item {
width: 160px;
font-size: @fontSize01;
color: #666666;
span {
display: block;
margin-bottom: 4px;
cursor: pointer;
}
span:nth-child(1) {
margin-bottom: 20px;
font-size: @fontSize02;
font-weight: 800;
color: #000000;
}
a {
text-decoration: none;
color: #666666;
}
}
}
.follow-us {
margin-bottom: 28px;
.other-link-item {
width: 96px;
font-size: @fontSize01;
color: #666666;
span {
display: block;
margin-bottom: 4px;
}
span:nth-child(1) {
margin-bottom: 20px;
font-size: @fontSize02;
font-weight: 800;
color: #000000;
}
}
}
.record-info {
height: 50px;
border-top: 1px #DDDDDD solid;
span {
margin: 0 6px;
font-size: @fontSize00;
color: #888888;
}
}
}
</style>
<template>
<!-- 通用组件 - 页面地图 -->
<div class="components-map row">
<div class="row align-c">
<img src="../assets/currency-map.png" alt="">
<span class="global-cursor" @click="$router.push('/')">首页</span>
</div>
<div class="row align-c" v-for="(item, index) in mapPath" :key="index">
<span class="global-cursor">></span>
<span class="global-cursor" @click="onRedirect(item)">{{item.text}}</span>
</div>
</div>
</template>
<script>
import iVue from '../main.js'
export default {
props: {
customPath: Array
},
data: function () {
return {
mapPath: []
}
},
watch: {
$route: function (funcNewValue, funcOldValue) {
},
customPath: {
handler: function (funcNewValue, funcOldValue) {
this.setMapPath()
},
deep: true,
immediate: true,
},
},
created: function () {
this.setMapPath()
},
methods: {
/**
* 地图跳转
* @function
* @param {object} funcItem
* @returns
*/
onRedirect: function (funcItem) {
if (funcItem.redirect) {
let funcRedirect = ''
for (let i = 0, len = this.mapPath.length; i < len; i++) {
funcRedirect = funcRedirect + this.mapPath[i].redirect
}
funcRedirect = funcRedirect.replace('null', '')
this.$router.push(funcItem.redirect + '?type=' + this.$route.query.type)
}
},
/**
* 设置地图
* @function
* @returns
*/
setMapPath: function () {
/**
* 设置地图
* @function
* @param {array } funcRouter
* @returns
*/
function readRouter (funcRouter) {
if (funcRouter.length === 0) {
return
}
// 统一 path 的格式为 /xxxx
for (let i = 0, len = funcRouter.length; i < len; i++) {
if (funcRouter[i].path.indexOf('/') === -1) {
funcRouter[i].path = '/' + funcRouter[i].path
}
}
for (let i = 0, len = funcRouter.length; i < len; i++) {
if (funcRouterCurrentPath.indexOf(funcRouter[i].path) === 0) {
if (funcRouterCurrentPath.charAt(funcRouter[i].path.length) === '' || funcRouterCurrentPath.charAt(funcRouter[i].path.length) === '/') {
funcRouterCurrentPath = funcRouterCurrentPath.replace(funcRouter[i].path, '')
if (funcRouter[i].children) {
funcMap.push({ 'text': funcRouter[i].children[0].mapText, 'redirect': funcRouter[i].path })
funcRouter = funcRouter[i].children
funcRouter.shift()
break
} else {
funcMap.push({ 'text': funcRouter[i].mapText, 'redirect': null })
funcRouter = []
break
}
}
}
}
if (funcRouterCurrentPath !== '') {
readRouter(funcRouter)
}
}
let funcMap = []
let funcRouterRaw = JSON.parse(JSON.stringify(iVue.$router.options.routes))
funcRouterRaw.shift()
let funcRouterCurrentPath = iVue.$router.history.current.path
if (this.customPath) {
this.mapPath = this.customPath
} else {
readRouter(funcRouterRaw)
this.mapPath = funcMap
}
}
}
}
</script>
<style lang="less">
.components-map {
height: 20px;
> div {
margin-right: 10px;
font-size: @fontSize01;
color: @colorGrey60;
span:nth-child(1) {
margin-right: 6px;
}
}
> div:last-child {
color: #2575FA;
}
img {
margin-right: 6px;
}
}
</style>
<template>
<!-- 通用组件 - 主要菜单 -->
<div class="components-navigation row con-c align-c">
<div class="global-maxwidth row con-b align-c">
<div class="logo">
<img src="../assets/logo@2x.png" alt="">
</div>
<div class="navigation row con-e">
<el-menu :default-active="active" class="el-menu-demo" mode="horizontal" @select="onSelect">
<el-menu-item index="home">首页</el-menu-item>
<el-menu-item index="bid">招标采购</el-menu-item>
<el-menu-item index="quote">竞价招标</el-menu-item>
<el-menu-item index="change">变更公告</el-menu-item>
<el-menu-item index="result">结果公告</el-menu-item>
<el-submenu index="information">
<template slot="title">招标资讯</template>
<el-menu-item index="information-policy">政策法规</el-menu-item>
<el-menu-item index="information-trends">招标动态</el-menu-item>
<el-menu-item index="information-help">帮助中心</el-menu-item>
</el-submenu>
<el-menu-item index="about">关于我们</el-menu-item>
</el-menu>
</div>
</div>
</div>
</template>
<script>
import iVue from '../main.js'
export default {
data () {
return {
active: '',
option: [
// 最高权重配置
{ index: 'quote', redirect: '/bid?type=0' },
{ index: 'bid', redirect: '/bid?type=2' },
{ index: 'change', redirect: '/bid?type=4' },
{ index: 'result', redirect: '/bid?type=6' },
{ index: 'information-policy', redirect: '/policy' },
{ index: 'information-trends', redirect: '/trends' },
{ index: 'information-help', redirect: '/help' },
{ index: 'about', redirect: '/about' },
// 次级权重配置
{ index: 'quote', redirect: '/bid/notice?type=0' },
{ index: 'bid', redirect: '/bid/notice?type=2' },
{ index: 'change', redirect: '/bid/notice?type=4' },
{ index: 'result', redirect: '/bid/notice?type=6' },
// 最低权重配置
{ index: 'home', redirect: '/' },
]
}
},
watch:{
$route: function () {
this.setActive()
}
},
created: function () {
this.setActive()
},
methods: {
onSelect: function (funcIndex) {
this.active = ''
for (let i = 0, len = this.option.length; i < len; i++) {
if (funcIndex === this.option[i].index) {
this.active = funcIndex
this.$router.push(this.option[i].redirect)
break
}
}
},
setActive: function () {
let funcRouterCurrentPath = iVue.$route.fullPath
if (funcRouterCurrentPath === '/') {
this.active = 'home'
return
}
this.active = ''
for (let i = 0, len = this.option.length; i < len; i++) {
if (funcRouterCurrentPath.indexOf(this.option[i].redirect) >= 0 && this.option[i].redirect !== '/') {
this.active = this.option[i].index
break
}
}
}
}
}
</script>
<style lang="less">
.components-navigation {
width: 100%;
height: 110px;
background: #FFFFFF;
.logo img {
width: 350px;
height: 40px;
}
.navigation {
// width: 734px;
.el-menu-demo {
border: none;
}
.el-menu-item,
.el-submenu {
width: 66px;
margin: 0 26px;
padding: 0;
color: #000000;
font-size: @fontSize02;
text-align: center;
.el-submenu__title {
width: 66px;
margin: 0;
padding: 0;
color: #000000;
border-bottom: none !important;
font-size: @fontSize02;
}
}
.is-active {
font-weight: 800;
color: @colorBlue !important;
border-bottom: 5px solid @colorRed !important;
}
}
}
</style>
<template>
<!-- 通用组件 - 侧边菜单 -->
<div class="components-navigation-top">
</div>
</template>
<script>
export default {
name: 'componentsNavigationTop',
data () {
return {
formSignIn: {
account: '', // 账号
password: '', // 密码
code: '' // 动态密令
},
rule: {
account: [
{ required: true, message: '请输入活动名称', trigger: 'blur' },
],
password: [
{ required: true, message: '请选择活动区域', trigger: 'change' }
],
code: [
{ required: true, message: '请选择活动区域', trigger: 'change' }
]
}
}
}
}
</script>
<style lang="less">
</style>
<template>
<!-- 通用组件 - 底部 -->
<div class="components-skill row">
<div v-for="(list, index) in skillList" :key="index" class="row">
<el-select v-model="selectItem[index]" :value="selectItem[index]" value-key="value" placeholder="请选择" @change="(item) => { onSelect(item, index) }">
<el-option v-for="item in list" :key="item.value" :label="item.label" :value="item"></el-option>
</el-select>
</div>
</div>
</template>
<script>
import iHost from '@/common/js/host.js'
import iRequest from '@/common/js/request/request.js'
export default {
props: {
identity: Number
},
data () {
return {
skillRawData: {},
skillList: [], // 列表数据
selectItem: [], // 选择对象
selectIndex: [], // 选择索引缓存
selectIndexBuffer: [], // 选择索引缓存
}
},
computed: {
componentSkill: function () {
return this.$store.state.componentSkill
},
},
watch: {
identity: {
handler: function (funcNewValue, funcOldValue) {
},
deep: true,
immediate: true,
},
componentSkill: {
handler: function (funcNewValue, funcOldValue) {
if (funcNewValue.length > 1 && funcNewValue[this.identity]) {
this.selectIndexBuffer = funcNewValue
}
},
deep: true,
immediate: true,
},
},
created: function () {
this.setSkillRawData()
},
methods: {
setSkillRawData: function () {
let funcSelectIndexBuffer
if (this.$store.getters.componentSkillData.length) {
funcSelectIndexBuffer = this.$store.getters.componentSkill[this.identity]
this.skillRawData = this.$store.getters.componentSkillData
this.selectIndexBuffer = funcSelectIndexBuffer ? funcSelectIndexBuffer : []
this.setSkillList(0, this.skillRawData)
} else {
iRequest.request(iHost.base + 'bid/common/getApiProjectTypeOptions', {}, 'json', 'get')
.then((funcResponse) => {
funcSelectIndexBuffer = this.$store.getters.componentSkill[this.identity]
this.skillRawData = funcResponse
this.selectIndexBuffer = funcSelectIndexBuffer ? funcSelectIndexBuffer : []
// 记录原始数据避免重复请求
this.setSkillList(0, this.skillRawData)
this.$store.commit('componentSkillData', this.skillRawData)
})
.catch((funcError) => {
console.log('iRequest', funcError)
})
}
},
setSkillList: function (funcRankIndex, funcSkillData) {
function createSkillList () {
if (!funcSkillData) return
let funcList = []
for (let i = 0, len = funcSkillData.length; i < len; i++) {
let funcItem = {
'index': i,
'value': funcSkillData[i].value,
'label': funcSkillData[i].label,
'idPath': funcSkillData[i].parentIds
}
funcList.push(funcItem)
}
This.$set(This.skillList, funcRankIndex, funcList)
This.$set(This.selectIndex, funcRankIndex, This.selectIndexBuffer[funcRankIndex] ? This.selectIndexBuffer[funcRankIndex] : 0)
This.$set(This.selectItem, funcRankIndex, This.skillList[funcRankIndex][This.selectIndex[funcRankIndex]])
This.saveSelect(This.selectIndex)
// 当子分类只有一个的时候无法触发组件 change 事件
// 因此主动触发一次选择当前分类事件
if (funcList.length === 1) {
let funcSkillDataBuffer = This.skillRawData
for (let i = 0, len = This.selectIndex.length; i < len; i++) {
if (funcSkillDataBuffer[This.selectIndex[i]].children) {
funcSkillDataBuffer = funcSkillDataBuffer[This.selectIndex[i]].children
}
}
funcRankIndex = funcRankIndex + 1
funcSkillData = funcSkillDataBuffer
createSkillList()
return
}
if (funcRankIndex < This.selectIndexBuffer.length) {
let funcSelectItem = funcSkillData[This.selectIndexBuffer[funcRankIndex]]
if (funcSkillData[This.selectIndexBuffer[funcRankIndex]].children) {
funcSkillData = funcSkillData[This.selectIndexBuffer[funcRankIndex]].children
funcRankIndex = funcRankIndex + 1
createSkillList()
}
}
}
let This = this
createSkillList()
},
saveSelect: function (funcSelectIndexBuffer) {
let funcComponentSkill = this.$store.getters.componentSkill
funcComponentSkill[this.identity] = funcSelectIndexBuffer
this.$store.commit('componentSkill', funcComponentSkill)
},
returnSelectId: function () {
let funcSelectId = []
let funcSkillData = this.skillRawData
for (let i = 0, len = this.selectIndex.length; i < len; i++) {
funcSelectId.push(funcSkillData[this.selectIndex[i]].value)
if (funcSkillData[this.selectIndex[i]].children) {
funcSkillData = funcSkillData[this.selectIndex[i]].children
}
}
this.$emit('change', funcSelectId) // 设置完成数据触发一次选择事件使父组件获取选择数据
},
onSelect: function (funcItem, funcRankIndex) {
// 清除选择分类之后所有数据
this.selectIndex[funcRankIndex] = funcItem.index
this.selectIndexBuffer[funcRankIndex] = funcItem.index
let funcSkillList = []
let funcSelectIndex = []
for (let i = 0; i <= funcRankIndex; i++) {
funcSkillList.push(this.skillList[i])
funcSelectIndex.push(this.selectIndex[i])
}
this.skillList = funcSkillList
this.selectIndex = funcSelectIndex
this.selectIndexBuffer = funcSelectIndex
// 保存当前选择数据
this.saveSelect(this.selectIndex)
// 定位选择分类查找下级分类
let funcIsChildren = false
let funcSkillData = this.skillRawData
for (let i = 0, len = this.selectIndex.length; i < len; i++) {
if (funcSkillData[this.selectIndex[i]].children) {
funcSkillData = funcSkillData[this.selectIndex[i]].children
funcIsChildren = true
} else {
funcIsChildren = false
}
}
if (funcIsChildren) {
this.setSkillList(funcRankIndex + 1, funcSkillData)
} else {
this.setSkillList(funcRankIndex, funcSkillData)
}
this.returnSelectId()
},
}
}
</script>
<style lang="less">
.components-skill {
> div {
.el-select {
width: 110px;
height: 46px;
margin-right: 4px;
}
> button {
width: 40px;
height: 40px;
border: 1px @colorGrey90 solid;
margin: 0;
padding: 0;
background: @colorWhite;
}
}
}
</style>
<template>
<!-- 信息模板 - 代理机构 -->
<div class="components-agency">
<div class="info">
<div class="info-item row align-c">
<span>招标代理机构:</span>
<span>{{componentAgency.name}}</span>
</div>
<div class="info-item row align-c">
<span>地址:</span>
<span>{{componentAgency.address}}</span>
</div>
<div class="info-item row align-c">
<span>联系人:</span>
<span>{{componentAgency.liaison}}</span>
</div>
<div class="info-item row align-c">
<span>联系电话:</span>
<span>{{componentAgency.phone}}</span>
</div>
<div class="info-item row align-c">
<span>邮箱:</span>
<span>{{componentAgency.email}}</span>
</div>
</div>
</div>
</template>
<script>
export default {
data () {
return {
}
},
computed: {
componentAgency: function () {
return this.$store.state.componentAgency
},
},
}
</script>
<style lang="less">
.components-agency {
.info {
.info-item {
margin: 10px 0;
span:nth-child(1) {
min-width: 160px;
margin-right: 10px;
text-align: right;
font-size: @fontSize02;
}
span:nth-child(2) {
text-align: left;
font-size: @fontSize01;
}
}
}
}
</style>
<template>
<!-- 信息模板 - 投标项目 -->
<div class="components-contract">
<!-- 招标类型 -->
<div v-if="viewControl === 'bid'">
<el-table :data="componentContract" stripe :header-cell-style="tableHeaderStyle">
<el-table-column type="index" label="合同包" width="80" align="center"></el-table-column>
<el-table-column prop="identity" label="合同包编号" min-width="140"></el-table-column>
<el-table-column prop="object" label="标约" min-width="230"></el-table-column>
<el-table-column prop="quantity" label="数量" min-width="120" align="center"></el-table-column>
<el-table-column prop="budget" label="预算总金额(元)" min-width="180" align="center"></el-table-column>
<el-table-column prop="timeClose" label="投标截止、开标时间" min-width="190"></el-table-column>
</el-table>
</div>
<!-- 中标类型 -->
<div v-if="viewControl === 'bidResult'">
<el-table :data="componentContract" stripe :header-cell-style="tableHeaderStyle">
<el-table-column type="index" label="合同包" width="80" align="center"></el-table-column>
<el-table-column prop="identity" label="合同包编号" min-width="140"></el-table-column>
<el-table-column prop="object" label="标的" min-width="230"></el-table-column>
<el-table-column prop="quantity" label="数量" min-width="120" align="center"></el-table-column>
<el-table-column prop="budget" label="预算总金额(元)" min-width="180" align="center"></el-table-column>
<el-table-column prop="timeClose" label="定标时间" min-width="190"></el-table-column>
</el-table>
<div class="components-contract-result col">
<div class="row align-c">
<span>中标(成交)供应商:上海宝光科技集团有限公司</span>
<span>中标(成交)金额:16900 元</span>
</div>
<div class="row align-c">
<span>中标(成交)供应商:华信纵横科技有限公司</span>
<span>中标(成交)金额:19300000 元</span>
</div>
</div>
</div>
<!-- 竞价类型 -->
<div v-if="viewControl === 'bidAmount'">
<el-table :data="componentContract" stripe :header-cell-style="tableHeaderStyle">
<el-table-column type="index" label="合同包" width="80" align="center"></el-table-column>
<el-table-column prop="identifier" label="标的" min-width="140"></el-table-column>
<el-table-column prop="content" label="参数要求" min-width="230"></el-table-column>
<el-table-column prop="quantity" label="数量" min-width="120" align="center"></el-table-column>
<el-table-column prop="amount" label="限价(元)" min-width="180" align="center"></el-table-column>
</el-table>
</div>
</div>
</template>
<script>
export default {
data () {
return {
noticeType: 0, // 项目类型
viewType: this.type,
viewControl: '',
componentContract: [],
tableHeaderStyle: {
color: '#000000',
background: '#F2F2F2'
},
}
},
computed: {
componentContract: function () {
return this.$store.state.componentContract
},
},
watch: {
componentContract: {
handler: function (funcNewValue, funcOldValue) {
},
deep: true,
immediate: true,
}
},
created: function () {
this.noticeType = this.$route.query.type ? Number(this.$route.query.type) : 0
this.initTableData()
},
methods: {
initTableData: function () {
console.log('initTableData', this.viewType)
let funcViewType = this.viewType
switch (funcViewType) {
case 0:
this.viewControl = 'bid'
break
case 1:
this.viewControl = 'bid'
break
case 2:
this.viewControl = 'bid'
break
case 3:
this.viewControl = 'bidResult'
break
case 4:
this.viewControl = 'bidAmount'
break
case 5:
this.viewControl = 'bidAmount'
break
case 6:
this.viewControl = 'bidResult'
break
case 7:
this.viewControl = 'bidResult'
break
}
}
}
}
</script>
<style lang="less">
.components-contract {
width: 100%;
min-height: 40px;
.components-contract-result {
width: 100%;
border: 1px #F2F2F2 solid;
border-top: none;
padding: 22px 0 22px 146px;
span {
margin: 10px 0;
text-align: left;
font-size: @fontSize01;
}
span:nth-child(1) {
width: 480px;
}
}
}
</style>
<template>
<!-- 下载模板 - 附件下载 -->
<div v-if="componentFile.length > 0" class="components-file">
<div class="row align-c">
<span>附件下载</span>
</div>
<div class="col">
<div class="list row align-c" v-for="(item, index) in componentFile" :key="index" @click="onDownload(item)">
<img src="../assets/notice-file.png" alt="">
<div class="row align-c">{{item.name}}</div>
<div class="row align-c">下载</div>
</div>
</div>
</div>
</template>
<script>
import iHost from '@/common/js/host.js'
export default {
data () {
return {
}
},
created: function () {
},
computed: {
componentFile: function () {
return this.$store.state.componentFile
},
},
watch: {
componentFile: {
handler: function (funcNewValue, funcOldValue) {
},
deep: true,
immediate: true,
}
},
methods: {
onDownload: function (funcItem) {
window.open(iHost.base + funcItem.url)
}
}
}
</script>
<style lang="less">
.components-file {
width: 100%;
padding-bottom: 20px;
background: #F2F2F2;
> div:nth-child(1) {
height: 60px;
padding: 0 24px;
border-bottom: 1px #E5E5E5 solid;
font-size: @fontSize04;
}
> div:nth-child(2) {
padding: 0 24px;
.list {
width: 100%;
margin-top: 20px;
font-size: @fontSize01;
cursor: pointer;
div:nth-child(2) {
flex-grow: 1;
padding-left: 4px;
text-decoration: underline;
cursor: pointer;
}
div:nth-child(3) {
cursor: pointer;
}
}
}
}
</style>
<template>
<!-- 信息模板 - 相关公告 -->
<div class="components-relation col con-b">
<div class="list">
<div class="item global-overflow-ellipsis" v-for="(item, index) in noticeBuffer" :key="index">
<span class="global-cursor" @click="onBidDetails(item)">{{item.title}}</span>
</div>
</div>
<div class="pagination row con-c align-c">
<div class="current row con-c align-c" v-for="(item, index) in noticeTotal" :key="index" @click="onPagination(index, 'current', searchOtherNotice)">
<div :class="index === searchOtherNotice.current ? 'active' : 'unactive'"></div>
</div>
</div>
</div>
</template>
<script>
import iFramePagination from '@/common/frame/pagination/pagination.js'
export default {
data () {
return {
noticeTotal: 1,
noticeBuffer: [],
searchOtherNotice: {
size: 8,
total: 0,
current: 0,
}
}
},
computed: {
componentNotice: function () {
return this.$store.state.componentNotice
},
},
watch: {
componentNotice: {
handler: function (funcNewValue, funcOldValue) {
this.setNotice()
},
deep: true,
immediate: true,
}
},
created: function () {
this.setNotice()
},
methods: {
setNotice: function () {
let funcSize = this.searchOtherNotice.size
let funcIndex = this.searchOtherNotice.current
this.noticeBuffer = []
this.noticeTotal = Math.ceil(this.componentNotice.length / this.searchOtherNotice.size)
for (let i = funcSize * funcIndex, len = funcSize * (funcIndex + 1); i < len; i++) {
if (this.componentNotice[i]) {
this.noticeBuffer.push(this.componentNotice[i])
}
}
},
onBidDetails: function (funcItem) {
this.$router.replace('/bid/notice?type=' + funcItem.type + '&id=' + funcItem.id)
},
onPagination: function (funcValue, funcType, funcUpdateObject) {
iFramePagination(funcValue, funcType, funcUpdateObject)
this.setNotice()
},
}
}
</script>
<style lang="less">
.components-relation {
width: 100%;
height: 200px;
.list {
display: flex;
flex-direction: row;
justify-content: space-between;
flex-wrap: wrap;
.item {
width: 50%;
margin-bottom: 20px;
padding-right: 30px;
font-size: @fontSize01;
::before {
content: '·';
display: inline-block;
width: 4px;
height: 4px;
margin-right: 8px;
}
}
}
.pagination {
.current {
width: 20px;
height: 20px;
> div {
width: 8px;
height: 8px;
border-radius: 50%;
}
}
.active {
background: #CF2F1E;
}
.unactive {
background: #00468C;
}
}
}
</style>
const output = {
urlFormat: function (value) {
if (!value) return value
let funcRegExp = new RegExp('^(https://)|(http://)', 'i')
if (!funcRegExp.test(value)) {
value = 'http://' + value
}
console.log('[filter]', value)
return value
}
}
export default output
\ No newline at end of file
import Vue from 'vue'
import App from './App'
import store from './store/store.js'
import filter from './filter/filter.js'
import router from './router/router.js'
Object.keys(filter).forEach(key => {
Vue.filter(key, filter[key])
})
import ElementUi from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import './common/css/reset.css'
import './common/css/flex.css'
Vue.use(ElementUi)
Vue.config.productionTip = false
/* eslint-disable no-new */
let output = new Vue({
'el': '#app',
'store': store,
'router': router,
'components': { App },
'template': '<App/>'
})
export default output
\ No newline at end of file
import Vue from 'vue'
import Router from 'vue-router'
// 解决跳转重复路径报错问题
let funcRouterPush = Router.prototype.push
Router.prototype.push = function push(funcPath) {
return funcRouterPush.call(this, funcPath).catch(funcError => funcError)
}
Vue.use(Router)
export default new Router({
mode : 'history',
routes: [
{ path: '/', name: 'home', mapText: '首页', component: () => import('@/view/home.vue') },
{ path: '/signIn', component: () => import('@/view/sign-in.vue'),
children: [
{ path: '/', name: 'signInStatus', mapText: '登录身份', component: () => import('@/view/sign-in-status.vue') },
{ path: 'input', name: 'signInInput', mapText: '登录', component: () => import('@/view/sign-in-input.vue') },
{ path: 'forget', name: 'signInForget', mapText: '忘记密码', component: () => import('@/view/sign-in-forget.vue') },
]
},
{ path: '/register', component: () => import('@/view/register.vue'),
children: [
{ path: '/', name: 'registerStatus', mapText: '注册身份', component: () => import('@/view/register-status.vue') },
{ path: 'supplier', name: 'registerSupplier', mapText: '供应商注册', component: () => import('@/view/register-supplier.vue') },
{ path: 'specialist', name: 'registerSpecialist', mapText: '专家注册', component: () => import('@/view/register-specialist.vue') },
]
},
{ path: '/bid', component: () => import('@/view/public/bid.vue'),
children: [
{ path: '/', name: 'bidList', mapText: '招标公告', component: () => import('@/view/public/bid-list.vue') },
{ path: 'notice', name: 'bidNotice', mapText: '公告详情', component: () => import('@/view/public/bid-notice.vue') },
{ path: 'buy', name: 'buy', mapText: '订单确认', component: () => import('@/view/public/bid-buy.vue') },
{ path: 'buyresult', name: 'buyResult', mapText: '完成报名', component: () => import('@/view/public/bid-buy-result.vue') },
]
},
{ path: '/policy', component: () => import('@/view/public/policy.vue'),
children: [
{ path: '/', name: 'policyList', mapText: '政策法规', component: () => import('@/view/public/policy-list.vue') },
{ path: 'details', name: 'policyDetails', mapText: '政策法规详情', component: () => import('@/view/public/policy-details.vue') },
]
},
{ path: '/trends', component: () => import('@/view/public/trends.vue'),
children: [
{ path: '/', name: 'trendsList', mapText: '招标动态', component: () => import('@/view/public/trends-list.vue') },
{ path: 'details', name: 'trendsDetails', mapText: '招标动态详情', component: () => import('@/view/public/trends-details.vue') },
]
},
{ path: '/question', component: () => import('@/view/public/question.vue'),
children: [
{ path: '/', name: 'question', mapText: '在线咨询', component: () => import('@/view/public/question-list.vue') },
{ path: 'input', name: 'questionInput', mapText: '填写咨询', component: () => import('@/view/public/question-input.vue') },
{ path: 'detail', name: 'questionDetail', mapText: '咨询详情', component: () => import('@/view/public/question-detail.vue') },
]
},
{ path: '/help', component: () => import('@/view/public/help.vue'),
children: [
{ path: '/', name: 'help', mapText: '帮助中心', component: () => import('@/view/public/help-list.vue') },
]
},
{ path: '/about', name: 'about', mapText: '关于我们', component: () => import('@/view/about.vue') },
// 用户中心 - 商家
{ path: '/supplier', component: () => import('@/view/personal/supplier.vue'),
children: [
{ path: '/', name: 'supplier', mapText: '工作台首页', component: () => import('@/view/personal/supplier-home.vue') },
{ path: 'bidding', name: 'supplierBid', mapText: '我的投标项目', component: () => import('@/view/personal/supplier-biding.vue') },
{ path: 'auction', name: 'supplierAuction', mapText: '我的竞价项目', component: () => import('@/view/personal/supplier-auction.vue') },
{ path: 'detail', name: 'supplierDetail', mapText: '详情', component: () => import('@/view/personal/supplier-notice.vue') },
{ path: 'orders', name: 'supplierOrders', mapText: '我的订单', component: () => import('@/view/personal/supplier-orders.vue') },
{ path: 'ordersdetail', name: 'supplierOrdersDetail', mapText: '订单详情', component: () => import('@/view/personal/supplier-orders-detail.vue') },
{ path: 'ordersbills', name: 'supplierOrdersBills', mapText: '申请开票', component: () => import('@/view/personal/supplier-orders-bills.vue') },
{ path: 'info', name: 'supplierInfo', mapText: '企业信息', component: () => import('@/view/personal/supplier-info.vue') },
{ path: 'infochange', name: 'supplierInfoChange', mapText: '修改企业信息', component: () => import('@/view/personal/supplier-info-change.vue') },
{ path: 'inforecord', name: 'supplierInfoRecord', mapText: '审核记录', component: () => import('@/view/personal/supplier-info-record.vue') },
{ path: 'infophone', name: 'supplierInfoPhone', mapText: '更换手机号码', component: () => import('@/view/personal/supplier-info-phone.vue') },
{ path: 'infopassword', name: 'supplierInfoPassword', mapText: '修改登录密码', component: () => import('@/view/personal/supplier-info-password.vue') },
{ path: 'notify', name: 'supplierNotify', mapText: '我的通知', component: () => import('@/view/personal/supplier-notify.vue') },
]
},
// 用户中心 - 专家
{ path: '/specialist', component: () => import('@/view/specialist/specialist.vue'),
children: [
{ path: '/', name: 'specialist', mapText: '我评标的项目', component: () => import('@/view/specialist/specialist-home.vue') },
{ path: 'info', name: 'specialistInfo', mapText: '我的信息', component: () => import('@/view/specialist/specialist-info.vue') },
{ path: 'infochange', name: 'specialistInfoChange', mapText: '修改我的信息', component: () => import('@/view/specialist/specialist-info-change.vue') },
{ path: 'inforecord', name: 'specialistInfoRecord', mapText: '审核记录', component: () => import('@/view/specialist/specialist-info-record.vue') },
{ path: 'infophone', name: 'specialistInfoPhone', mapText: '更换手机号码', component: () => import('@/view/specialist/specialist-info-phone.vue') },
{ path: 'infopassword', name: 'specialistInfoPassword', mapText: '修改登录密码', component: () => import('@/view/specialist/specialist-info-password.vue') },
{ path: 'notify', name: 'specialistNotify', mapText: '我的通知', component: () => import('@/view/specialist/specialist-notify.vue') },
]
},
{ path: '*', name: '404', meta: { title: '404' }, component: () => import('@/view/404.vue')}
],
scrollBehavior(to, from, savedPosition) {
return {
x: 0,
y: 0,
}
}
})
\ No newline at end of file
localStorage
请求令牌 - {string} token: ''
刷新令牌 - {string} refresh: ''
专家登录信息 - {object} signInInfo: {} | { phone: '', password: '' }
供应登录信息 - {object} signInInfo: {} | { phone: '', password: '' }
登录身份 - {string} identity: '' - 1 - 专家, 2 - 供应商
注册状态 - {string} register: '' - 0 - 审核中, 1 - 通过, 2 - 不通过
sessionStorage
\ No newline at end of file
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
isSignIn: false, // 登录状态
redirectPath: '', // 重定向的路径
notify: '', // 通知变更
info: {},
// 公告详情组件
componentProject: {},
componentProgress: {},
componentContract: [],
componentAgency: {},
componentFile: [],
componentNotice: [],
areaSelection: [],
contractSelection: {},
// 专家注册组件
componentSkill: [],
componentSkillData: {},
identity: '', // 登录身份
identityState: 0, // 身份状态,0 - 审核,1 - 通过,2 - 禁止
identityGrade: 0, // 身份等级
// 临时数据
project: {
'identity': '',
'name': '',
'buy': '',
'company': '',
'liaison': '',
'phone': '',
'release': '',
'area': '',
'contract': []
},
agency: {
'name': '-',
'area': '-',
'liaison': '-',
'phone': '-',
'email': '-'
},
contract: [],
},
mutations: {
info: function (state, value) {
state.info = value
},
notify: function (state, value) {
state.notify = value
},
componentProject: function (state, value) {
state.componentProject = value
},
componentProgress: function (state, value) {
state.componentProgress = value
},
componentContract: function (state, value) {
state.componentContract = value
},
componentAgency: function (state, value) {
state.componentAgency = value
},
componentFile: function (state, value) {
state.componentFile = value
},
componentNotice: function (state, value) {
state.componentNotice = value
},
areaSelection: function (state, value) {
state.areaSelection = value
},
contractSelection: function (state, value) {
state.contractSelection = value
},
componentSkill: function (state, value) {
state.componentSkill = value
},
componentSkillData: function (state, value) {
state.componentSkillData = value
},
redirectPath: function (state, value) {
state.redirectPath = value
},
isSignIn: function (state, value) {
state.isSignIn = value
},
identity: function (state, value) {
state.identity = value
},
identityState: function (state, value) {
state.identityState = value
},
infoProject: function (state, value) {
state.infoProject = value
},
// 临时写法后期需要重新整理
bidDetailProject: function (state, value) {
state.project = value
},
bidDetailAgency: function (state, value) {
state.agency = value
},
bidDetailContract: function (state, value) {
state.contract = value
},
},
getters: {
redirectPath: function (state) {
return state.redirectPath
},
info: function (state) {
return state.info
},
notify: function (state) {
return state.notify
},
componentProject: function (state) {
return state.componentProject
},
componentProgress: function (state) {
return state.componentProgress
},
componentAgency: function (state) {
return state.componentAgency
},
componentFile: function (state) {
return state.componentFile
},
componentNotice: function (state) {
return state.componentNotice
},
areaSelection: function (state) {
return state.areaSelection
},
contractSelection: function (state) {
return state.contractSelection
},
componentSkill: function (state) {
return state.componentSkill
},
componentSkillData: function (state) {
return state.componentSkillData
},
isSignIn: state => state.isSignIn,
identity: state => state.identity,
identityState: state => state.identityState,
bidDetailProject: state => state.project,
bidDetailAgency: state => state.agency,
bidDetailContract: state => state.contract,
}
})
\ No newline at end of file
<template>
<div class="not-found">
<span>404</span>
</div>
</template>
<script>
import iRule from '@/common/js/request/request.js'
import iRequest from '@/common/js/request/request.js'
export default {
components: {},
data: function () {
return {
}
},
created: function () {
this.$router.push('/')
},
watch: {},
methods: {},
}
</script>
<style lang="less">
</style>
<template>
<div class="about col align-c">
<componentHeader></componentHeader>
<componentNavigation></componentNavigation>
<div class="about-banner">
<img src="../assets/home-banner.png" alt="">
</div>
<div class="global-maxwidth about-us row con-c">
<div class="about-us-info">
<p><span>厦门建发集团有限公司</span>系厦门市属国有企业,创立于1980年12月,经过三十多年的创新与变革,公司已发展成为注册资本65.5亿元、年营业收入超过2800亿元、资产总额超过2500亿元的大型实业投资企业集团,业务涵盖供应链运营、房地产开发、旅游酒店、会展业、医疗、投资等,排名2019年度《财富》"世界500强"第277位、2019中国企业500强第71位、中国服务业500强第39位。</p>
<p>今后集团将通过扩大现有核心产业的投资、适度增强现有新兴产业投资、积极对现有其他投资企业进行资本运作,并尝试一些新领域投资,将采取传统产业项目与高科技项目相结合、产业投资与战略投资、风险投资相结合、独立投资经营与合资合作相结合的策略,促进重点领域核心竞争力的形成与升级,实现投资收益的较大增长和核心产业品牌增值,促使集团稳步发展。</p>
<p><span>地址:厦门市思明区吕岭路1733号创想中心1801单元</span></p>
<p><span>电话:0592-5859311</span></p>
</div>
<div class="about-us-amp">
<!-- <componentBaiduMap class="bm-view" ak="YOUR_APP_KEY"></componentBaiduMap> -->
<img src="../assets/about-map.png" alt="">
</div>
</div>
<componentFooter></componentFooter>
</div>
</template>
<script>
import iHeader from '@/components/currency-header.vue'
import iNavigation from '@/components/currency-navigation.vue'
import iFooter from '@/components/currency-footer.vue'
import iBaiduMap from 'vue-baidu-map/components/map/Map.vue'
export default {
components: {
componentHeader: iHeader,
componentNavigation: iNavigation,
componentFooter: iFooter,
componentBaiduMap: iBaiduMap
},
data: function () {
return {
}
}
}
</script>
<style lang="less">
.about {
width: 100%;
background-image: url(@backgroundImageUrl);
background-repeat: no-repeat;
.about-banner {
img {
width: 100%;
}
}
.about-us {
width: 1200px;
height: 508px;
margin: 50px 0;
padding: 54px 44px 54px 32px;
background: @colorWhite;
box-shadow: 0px 0px 20px 0px rgba(41, 41, 41, 0.05);
.about-us-info {
margin-right: 26px;
> p {
margin-bottom: 8px;
line-height: 2.0;
font-size: @fontSize02;
color: @colorGrey60;
text-indent: 2em;
span {
color: @colorGrey00;
}
}
}
}
.bm-view {
width: 100%;
height: 300px;
}
}
</style>
\ No newline at end of file
<template>
<div class="public-information">
<span>public-information</span>
</div>
</template>
<script>
export default {
name: 'publicInformation'
}
</script>
<style lang="less">
</style>
\ No newline at end of file
<template>
<!-- 通用组件 - 头部 -->
<div class="components-personal-header row con-b align-c" @mouseleave="onMenuControl('leave')">
<div class="title">
<span>我的工作台</span>
</div>
<div class="personal row align-c">
<img class="global-cursor" src="../../../assets/currency-map.png" alt="" @click="$router.push('/')">
<el-badge :is-dot="isNewNotice" class="row align-c">
<img class="global-cursor" src="../../../assets/notice-tip.png" alt="" @click="$router.push('/supplier/notify')">
</el-badge>
<span>{{info ? info.name : ''}}</span>
<span class="global-cursor" @click="onSignOut()">退出</span>
</div>
</div>
</template>
<script>
import iHost from '@/common/js/host.js'
import iRequest from '@/common/js/request/request.js'
import iToken from '@/common/js/token.js'
export default {
data: function () {
return {
isNewNotice: false,
winMenu: false,
}
},
computed: {
info: function () {
return this.$store.state.info
},
notify: function () {
return this.$store.state.notify
},
},
watch: {
info: {
handler: function (funcNewValue, funcOldValue) {
},
deep: true,
immediate: true,
},
notify: {
handler: function (funcNewValue, funcOldValue) {
this.queryNotice()
},
deep: true,
immediate: true,
}
},
created: function () {
this.init()
this.queryNotice()
},
methods: {
/**
* 检查登录状态
* @function
* @returns
*/
init: function () {
let funcToken = localStorage.getItem('token')
if (!funcToken) {
this.$router.push('/signIn')
return
}
switch (iToken.state(funcToken)) {
case 'valid':
this.$store.commit('isSignIn', true)
this.$store.commit('info', JSON.parse(localStorage.getItem('info')))
break
case 'refresh':
this.$store.commit('isSignIn', true)
this.$store.commit('info', JSON.parse(localStorage.getItem('info')))
iRequest.request(iHost.base + 'bid/zLogin/refreshToken', { 'refreshToken': localStorage.getItem('refresh') }, 'json', 'get')
.then((funcResponse) => {
localStorage.setItem('token', funcResponse.token)
localStorage.setItem('refresh', funcResponse.refreshToken)
this.queryUserInfo()
})
.catch((funcError) => {
this.$message.error(funcError.message)
})
break
case 'invalid':
this.onSignOut()
break
}
},
queryNotice: function () {
iRequest.request(iHost.base + 'bid/zNotification/countUnread', { 'userType': 2 }, 'json', 'post')
.then((funcResponse) => {
if (funcResponse.count > 0) {
this.isNewNotice = true
} else {
this.isNewNotice = false
}
})
.catch((funcError) => {
this.$message.error(funcError.message)
})
},
queryUserInfo: function () {
switch (this.info.identity) {
case 1:
iRequest.request(iHost.base + 'bid/zUserExpert/getLoginUserInfo', {}, 'json', 'get')
.then((funcResponse) => {
// 0 - 审核
// 1 - 通过
// 2 - 拒绝
this.info.name = funcResponse.name
this.info.register = Number(funcResponse.state)
this.$store.commit('info', this.info)
localStorage.setItem('info', JSON.stringify(this.info))
})
.catch((funcError) => {
this.$message.error(funcError.message)
})
break
case 2:
iRequest.request(iHost.base + 'bid/zUserCompany/getLoginUserInfo', {}, 'json', 'get')
.then((funcResponse) => {
// 0 - 审核
// 1 - 通过
// 2 - 拒绝
this.info.name = funcResponse.companyName
this.info.register = Number(funcResponse.state)
this.$store.commit('info', this.info)
localStorage.setItem('info', JSON.stringify(this.info))
})
.catch((funcError) => {
this.$message.error(funcError.message)
})
break
}
},
onMenuControl: function (funcType) {
switch (funcType) {
case 'enter':
this.winMenu = true
break
case 'leave':
this.winMenu = false
break
}
},
onSignOut: function () {
this.$router.push('/')
this.$store.commit('info', null)
this.$store.commit('isSignIn', false)
this.$store.commit('redirectPath', null)
localStorage.clear()
}
}
}
</script>
<style lang="less">
.components-personal-header {
width: 100%;
height: 60px;
padding: 0 40px;
background-image: url(../../../assets/bg-title.png);
background-repeat: no-repeat;
.title {
color: #FFFFFF;
}
.personal {
position: relative;
height: 100%;
color: #FFFFFF;
span {
margin-left: 20px;
}
img {
width: 16px;
height: 16px;
margin-left: 12px;
}
}
}
</style>
<template>
<!-- 信息模板 - 项目进度 -->
<div class="components-personal-progress row align-c">
<!-- 竞标公告进度样式 -->
<div class="row">
<!-- 节点显示 -->
<div class="personal-node-line" :style="'background-image: linear-gradient(to right, #CF2F1D 0%, #CF2F1D ' + progressWidth * progressState + '%, #FFFFFF ' + progressWidth * progressState + '%);'"></div>
<div class="personal-node con-b row">
<div class="col con-c align-c">
<div class="personal-node-point"></div>
<div class="personal-node-name">{{progressNode[0].text}}</div>
<div class="personal-node-time">{{progressNode[0].time}}</div>
</div>
<div class="col con-c align-c">
<div :class="progressState >= 2 ? 'personal-node-point' : 'personal-node-point-unactive'"></div>
<div class="personal-node-name">{{progressNode[1].text}}</div>
<div class="personal-node-time">{{progressNode[1].time}}</div>
</div>
<div class="col con-c align-c">
<div :class="progressState > 3 ? 'personal-node-point' : 'personal-node-point-unactive'"></div>
<div class="personal-node-name">{{progressNode[2].text}}</div>
<div class="personal-node-time">{{' '}}</div>
</div>
</div>
</div>
</div>
</template>
<script>
import iMiment from 'miment'
import iTime from '@/common/js/time.js'
export default {
data () {
return {
detailsType: 0,
progressNode: [],
progressWidth: 25,
progressState: 1,
}
},
computed: {
componentProject: function () {
return this.$store.state.componentProject
},
componentProgress: function () {
return this.$store.state.componentProgress
}
},
watch: {
componentProject: {
handler: function (funcNewValue, funcOldValue) {
},
deep: true,
immediate: true,
},
componentProgress: {
handler: function (funcNewValue, funcOldValue) {
if (JSON.stringify(funcNewValue) !== '{}') {
this.setProgressTime(funcNewValue)
this.setOperate(funcNewValue)
}
},
deep: true,
immediate: true,
}
},
created: function () {
this.progressNode = [
{ 'text': ' ', 'time': ' ' },
{ 'text': ' ', 'time': ' ' },
{ 'text': ' ', 'time': ' ' },
]
},
methods: {
/**
* 设置进度时间数据
* @function
* @param {object} funcProgressData - 进度原始数据
* @returns
*/
setProgressTime: function (funcProgressData) {
this.progressNode = [
{
text: funcProgressData.text[0],
time: iMiment(funcProgressData.timestamp[0]).format('YYYY-MM-DD hh:mm')
},
{
text: funcProgressData.text[1],
time: iMiment(funcProgressData.timestamp[1]).format('YYYY-MM-DD hh:mm') + ' - ' + iMiment(funcProgressData.timestamp[2]).format('YYYY-MM-DD hh:mm')
},
{
text: funcProgressData.text[2],
time: iMiment(funcProgressData.timestamp[3]).format('YYYY-MM-DD hh:mm')
},
]
if (this.componentProject.noticeType === 0) {
this.progressNode[2].time = ' '
}
},
/**
* 设置按钮数据
* @function
* @param {object} funcProgressData - 进度原始数据
* @returns
*/
setOperate: function (funcProgressData) {
// 计算进度状态
let funcIndex = 0
for (funcIndex; funcIndex < funcProgressData.timestamp.length; funcIndex++) {
if (iTime() < funcProgressData.timestamp[funcIndex]) {
break
}
}
this.progressState = funcIndex
},
}
}
</script>
<style lang="less">
.components-personal-progress {
width: 100%;
background: #F2F2F2;
> div {
position: relative;
width: 100%;
.personal-node-line {
position: absolute;
top: 24px;
left: 150px;
width: calc(100% - 300px);
height: 10px;
}
.personal-node {
position: relative;
width: 100%;
.personal-node-point {
width: 24px;
height: 24px;
margin-bottom: 8px;
border-radius: 50%;
border: 2px #FFFFFF solid;
background: #CF2F1D;
}
.personal-node-point-unactive {
width: 24px;
height: 24px;
margin-bottom: 8px;
border-radius: 50%;
border: 2px #FFFFFF solid;
background: #E5E5E5;
}
.personal-node-name {
margin-bottom: 4px;
font-size: @fontSize02;
}
.personal-node-time {
margin-bottom: 4px;
font-size: @fontSize01;
}
> div {
z-index: 5;
width: 300px;
height: 120px;
}
}
}
}
</style>
<template>
<!-- updata:06-06 -->
<!-- 信息模板 - 投标项目 -->
<div class="component-project">
<!-- 竞价报价公告 -->
<div v-if="noticeType === 0" class="info">
<div class="item-text row align-c">
<span>竞价项目编号:</span>
<span>{{componentProject.projectIdentity}}</span>
</div>
<div class="item-text row align-c">
<span>竞价项目名称:</span>
<span>{{componentProject.projectName}}</span>
</div>
<div class="item-text row align-c">
<span>采购单位:</span>
<span>{{componentProject.buyCompany}}</span>
</div>
<div class="item-text row align-c">
<span>采购单位性质:</span>
<span>{{componentProject.buyCompanyType}}</span>
</div>
<div class="item-text row align-c">
<span>采购单位联系人:</span>
<span>{{componentProject.buyLiaison}}</span>
</div>
<div class="item-text row align-c">
<span>联系电话:</span>
<span>{{componentProject.buyPhone}}</span>
</div>
<div class="item-text row align-c">
<span>竞价时间:</span>
<span>{{componentProject.timeBegin + ' - ' + componentProject.timeEnd}}</span>
</div>
</div>
<!-- 招标采购公告 -->
<div v-if="noticeType === 2" class="info">
<div class="item-text row align-c">
<span>项目编号:</span>
<span>{{componentProject.projectIdentity}}</span>
</div>
<div class="item-text row align-c">
<span>项目名称:</span>
<span>{{componentProject.projectName}}</span>
</div>
<div class="item-text row align-c">
<span>采购方式:</span>
<span>{{componentProject.buyWay}}</span>
</div>
<div class="item-text row align-c">
<span>采购单位:</span>
<span>{{componentProject.buyCompany}}</span>
</div>
<div class="item-text row align-c">
<span>采购单位联系人:</span>
<span>{{componentProject.buyLiaison}}</span>
</div>
<div class="item-text row align-c">
<span>联系电话:</span>
<span>{{componentProject.buyPhone}}</span>
</div>
<div class="item-text row align-c">
<span>文件发售时间:</span>
<span>{{componentProject.timeBegin + ' - ' + componentProject.timeEnd}}</span>
</div>
<!-- 单一合同 -->
<div v-if="!componentProject.isPackage" class="item-text row align-c">
<span>文件售价:</span>
<span>{{componentContract[0] ? componentContract[0].budget + ' 元' : ''}}</span>
</div>
<div v-if="!componentProject.isPackage" class="item-text row align-c">
<span>投标截止、开标时间:</span>
<span>{{componentProject.timeClose}}</span>
</div>
<div class="item-text row align-c">
<span>开标地点:</span>
<span>{{componentProject.address}}</span>
</div>
</div>
<!-- 资格预审公告 -->
<div v-if="noticeType === 3" class="info">
<div class="item-text row align-c">
<span>项目编号:</span>
<span>{{componentProject.projectIdentity}}</span>
</div>
<div class="item-text row align-c">
<span>项目名称:</span>
<span>{{componentProject.projectName}}</span>
</div>
<div class="item-text row align-c">
<span>采购方式:</span>
<span>{{componentProject.buyWay}}</span>
</div>
<div class="item-text row align-c">
<span>采购单位:</span>
<span>{{componentProject.buyCompany}}</span>
</div>
<div class="item-text row align-c">
<span>采购单位联系人:</span>
<span>{{componentProject.buyLiaison}}</span>
</div>
<div class="item-text row align-c">
<span>联系电话:</span>
<span>{{componentProject.buyPhone}}</span>
</div>
<div class="item-text row align-c">
<span>领取资格预审文件时间:</span>
<span>{{componentProject.timeBegin + ' - ' + componentProject.timeEnd}}</span>
</div>
<!-- 单一合同 -->
<div v-if="!componentProject.isPackage" class="item-text row align-c">
<span>文件售价:</span>
<span>{{componentContract[0] ? componentContract[0].budget + ' 元' : ''}}</span>
</div>
<div v-if="!componentProject.isPackage" class="item-text row align-c">
<span>申请文件提交截止、开标时间:</span>
<span>{{componentProject.timeClose}}</span>
</div>
<div v-if="!componentProject.isPackage" class="item-text row align-c">
<span>开标地点:</span>
<span>{{componentProject.address}}</span>
</div>
</div>
</div>
</template>
<script>
export default {
data: function () {
return {
tableHeaderStyle: {
color: '#000000',
background: '#F2F2F2'
},
noticeType: '',
}
},
computed: {
componentProject: function () {
return this.$store.state.componentProject
},
componentContract: function () {
return this.$store.state.componentContract
},
},
watch: {
$route: function () {
this.noticeType = this.$route.query.type ? Number(this.$route.query.type) : 0
},
componentContract: {
handler: function (funcNewValue, funcOldValue) {
},
deep: true,
immediate: true,
}
},
created: function () {
this.noticeType = this.$route.query.type ? Number(this.$route.query.type) : 0
},
methods: {
}
}
</script>
<style lang="less">
.component-project {
.info {
.item-text {
margin: 16px 0;
span:nth-child(1) {
min-width: 180px;
margin-right: 10px;
text-align: right;
font-size: @fontSize02;
}
span:nth-child(2) {
text-align: left;
font-size: @fontSize01;
}
}
}
}
</style>
<template>
<!-- 用户中心组件 - 侧边菜单 -->
<div class="components-personal-sidebar row con-b align-c">
<el-menu class="sidebar" @select="onSelectItem">
<el-menu-item v-if="info ? info.register === 1 : true" index="1">
<span slot="title">工作台首页</span>
</el-menu-item>
<el-submenu v-if="info ? info.register === 1 : true" index="2">
<template slot="title">
<span>投标管理</span>
</template>
<el-menu-item index="2-1">我投标的项目</el-menu-item>
<el-menu-item index="2-2">我竞价的项目</el-menu-item>
</el-submenu>
<el-menu-item v-if="info ? info.register === 1 : true" index="3">
<span slot="title">我的订单</span>
</el-menu-item>
<el-submenu index="4">
<template slot="title">
<span>账号管理</span>
</template>
<el-menu-item index="4-1">企业信息</el-menu-item>
<el-menu-item index="4-2">更换手机号码</el-menu-item>
<el-menu-item index="4-3">修改登录密码</el-menu-item>
</el-submenu>
</el-menu>
</div>
</template>
<script>
export default {
data: function () {
return {
}
},
computed: {
info: function () {
return this.$store.state.info
},
},
watch: {
info: {
handler: function (funcNewValue, funcOldValue) {
},
deep: true,
immediate: true,
},
},
methods: {
onSelectItem: function (funcIndex) {
switch (funcIndex) {
case '1':
this.$router.push('/supplier')
break
case '2-1':
this.$router.push('/supplier/bidding')
break
case '2-2':
this.$router.push('/supplier/auction')
break
case '3':
this.$router.push('/supplier/orders')
break
case '4-1':
this.$router.push('/supplier/info')
break
case '4-2':
this.$router.push('/supplier/infophone')
break
case '4-3':
this.$router.push('/supplier/infopassword')
break
}
},
}
}
</script>
<style lang="less">
.components-personal-sidebar {
.sidebar {
width: 220px;
height: 100%;
min-height: 908px;
background: #FBFBFB;
border: 1px solid #EFEFEF;
.el-menu-item {
height: 50px;
}
div,
ul,
li {
background: #FBFBFB;
}
}
}
</style>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment